MongoDB - Insert 2 documents, each in another collection but share ObjectId - javascript

I have this question:
I want to insert 2 documents into 2 collections.
One is for user and one is for company.
Both inserts are requested via api.
In created(Inserted) company I want to know, which user[Created/inserted] create this company. And in user i want to have _id of company that he inserted.
User
{
_id: "userGeneratedId",
companyId : Company._id
}
Company
{
_id: "companyGeneratedId",
registeredByID : user._id
}
How can this be done?
Thank you,
Dufino

There are two ways to go about this
The first and easy way
Add new fields to your user and company model. maybe call it userSaveId or whatever you choose. Now you will insert same unique id to these new fields fields, so that when you are retrieving a company, you can just retrieve it based on that ID.
The second way this could be done is by performing 4 operations. 2 insert operations and two update operations. Note that this would slightly increase the response time of your operations.
Suppose you have inserted a user and company, get the IDs of both the user document and company document as such:
const user = User.save(yourData);
const company = Company.save(yourCompanyData);
Afterwards get the ids and use it to update the documents that are already stored as such:
const userId = user._id;
const companyId = company._id;
User.updateOne({_id: userId}, {$set: {companyId: companyId}});
Company.updateOne({_id: companyId}, {$set: {registeredByID: userId}});
So the complete code would be this:
const user = User.save(yourData);
const company = Company.save(yourCompanyData);
const userId = user._id;
const companyId = company._id;
User.updateOne({_id: userId}, {$set: {companyId: companyId}});
Company.updateOne({_id: companyId}, {$set: {registeredByID: userId}});

Related

Add, update and read sub-collection in firestore using Angular (#angular/fire)

I am trying to learn firebase. I am making a project like Linkedin using Angular and Firebase.
I am using the #angular/fire package in my project.
So far I have done authentication and adding some basic info of a user. I have users collection where each documentId have information like name, email and etc
Now my next goal is to create a work experience section. Since a user can have multiple work experience.
I have to decided to proceed with sub-collection under each user document id instead of creating a separate collection for work-experience.
Now I am having a bit trouble how to add sub-collection in my users collection.
A user can only add/update one experience at a time. My UI will be something similar to Linkedin. When the 'Add Experience' button is clicked a modal will pop up and there will be a form inside the form with fields such as jobTitle, companyName and etc. So once the submit is clicked I want to save that data under the work-experience sub-collection with a unique documentId.
Currently I am adding my basic info like this
Adding
addUser(user: any): Observable<void> {
const ref = doc(this.firestore, 'users', user.uid);
return from(setDoc(ref, user));
}
Updating
updateUser(user: any): Observable<void> {
const ref = doc(this.firestore, 'users', user.uid);
return from(updateDoc(ref, { ...user }));
}
Now I want to add sub-collection called work-experience under the users collection.
From your other question I think you need to add a sub-collection which contains a document with ID work-experience.
If my assumption is correct, do as follows to create the DocumentReference to this Document:
const workExperienceDocRef = doc(this.firestore, `users/${user.uid}/sub-sections/work-experience`);
Note: Make sure to use back ticks.
And then you can set the data of this doc as follows, for example:
return from(setDoc(workExperienceDocRef, {experiences: [{years: "2015-2018", company: "comp1"}, {years: "2018-2021", company: "comp2"}]}));
If you want to create a sub-collection for the user's document, do as follows:
const userSubCollection = collection(this.firestore, `users/${user.uid}/sub-collection`);
Then you can use the addDoc() method, which will automatically generate the document ID.:
const docRef = await addDoc(userSubCollection, {
foo: "bar",
bar: "foo"
});

Add a new field in mongoDB from another collection independently?

I have two collections: profiles and contents
The profiles collection looks like this:
{
_id: ObjectId('618ef65e5295ba3132c11111'),
blacklist: [ObjectId('618ef65e5295ba3132c33333'), ObjectId('618ef65e5295ba3132c22222')],
//more fields
}
The contents collection looks like this:
{
_id: ObjectId('618ef65e5295ba3132c00000'),
owner: ObjectId('618ef65e5295ba3132c22222'),
//more fields
}
What I need is to get those contents where owner is not included in the blacklist. I thought about to put the blacklist field into the contents documents. I could get the profile by id separately (in another query) and set it manually in the aggregation where I get the contents, but this requires one extra connection.
So my question is: Is there a way to add my profile into each document of another collection? keep in mind that I have the profile ID.
Here is some psuedo code on how it "should" look like, First fetching the blacklists owners, then using that variable as a parameter in the pipeline.
const profileId = input;
const blackListIds = await db.getCollection('profiles').distinct('blacklist', { _id: profileId });
const aggregationResults = await db.getCollection('contents').aggregate([
{
$match: {
owner: {$nin: blackListIds}
}
}
... continuation of pipeline ...
])

How can I access a specific attribute of a specific document in a mongoDB collection?

To summarize, I am working with 2 collections - 'usercollection' and 'groupcollection' and I would like to associate users with groups. I don't want to have 2 copies of all the user documents so I have a unique ID attribute for each user that I want to use to associate specific users with specific groups. This is all running on a localhost webserver so I'm getting the input from an html page with a form in it where you enter 'username' and 'groupname'. I tried using the .distinct() function with query as 'username' and the target field/attribute as 'uid'.
// Set our internal DB variable
var db = req.db;
// Get our form values. These rely on the "name" attributes
var userName = req.body.username;
// Set query and options for searching usercollection
var query = {"username" : userName};
const fieldName = "uid";
// Set our collections
var users = db.get('usercollection');
// Get UID corresponding to username
var uidToAdd = users.distinct(fieldName, query);
This is what I attempted (with some other lines that aren't relevant taken out) but it just returned a null object so I'm at a bit of a loss. Also, I'm still a beginner with nodejs/javascript/mongoDB so the more informative the answer the better! When I do the same code in the mongo shell I can get the actual value of the 'uid' attribute so I really don't know what's going wrong
I am not sure I am following you. But if I understood correctly, if you want to make a relationship between 'usercollection' and 'groupcolletion', you can simply create those 2 collections and each user in 'usercollection' should have a field with 'groupid' as a reference. In this way, you can access 'groupcollection' easily.
Here is an example with using mongoose.
In User model
...
groupId: {
type: mongoose.Schema.Types.ObjectID
ref: "Group"
}
...
Later you can also use 'populate' to fetch 'Group' information.
...
let data = await User.findById(id).populate('groupId');
...

Mongoose find - return all that match at least one from query

I'm building an application (MongoDB database) where user can register an account. The account model has 3 value's that should be unique: ID, Username & Email. I'm using Mongoose v5.5.5 for querying etc.
When someone wants to register a new account, I want to do a query (findOne or find) to see if there is a user with that ID OR username OR mail. I thought the code below would work.
let query = {
'id': sanitized.id,
'username': sanitized.username,
'mail': sanitized.mail
}
AccountModel.find(query, (error, data) => {
// Handle result
})
So lets say there is a user with as username user1 and as email user1#mail.com.
Now another user wants to register user the username user2 but with the same email as user1.
How can I perform a query that matches on OR the username OR the mail so that I can tell either of those is already being used by another user?
I prefer using one single query to keep the code clean, but I couldn't find a solution yet. Hope someone can help.
You can use $or aggregation to pass different queries
let query = {
'$or': [
{'id': sanitized.id},
{'username': sanitized.username},
{'mail': sanitized.mail}
]
}
This will return all documents matching any of the queries. In my system what I did is actually two queries in Promise.all, one for userName, one for userEmail, for easier validation of the data (result[0] = userName, result[1] = userEmail)
Eg
Promise.all([
AccountModel.find({'username': sanitized.username}).exec(),
AccountModel.find({'mail': sanitized.mail}).exec(),
]).then(validation => {
if(validation[0]){// username taken }
if(validation[1]){// email taken }
})
You can still you the Find method just when you do your query use the $or operator and here's an example

Firebase get all usernames & user Id starting with user entered character

I am trying to only fetch username and user IDs that only start with the User entered text.
Below is my firebase database:
As you can see the database contains a list of user Ids which contains the username.
For Example: If the user enters M in the search box, Query should
return Mr Jois and it's the corresponding user ID.
I am trying to do this using javascript. Below is my code:
function* searchUsers(action) {
const database = firebase.database();
const ref = database.ref('users');
try {
console.log('about to fetch filters users');
const query = ref.orderByChild('username').startAt(action.searchText);
const snapshot = yield call([query, query.once], 'value');
console.log('done fetching users');
console.log(snapshot);
}
catch(error){
console.log(error);
}
}
But I am not getting the expected results. Can someone please tell me how to query the result to get the expected result?
Firebase Database queries do a prefix match, not a contains. But since you only specify startAt(...) the query matches all users from the ones whose name starts with the prefix, including all names after it. If you only want results that start with the prefix string, you'll want to also use endAt(...):
const query = ref.orderByChild('username').startAt(action.searchText)endA‌t(action.searchText+‌​"\uf8ff");
const snapshot = yield call([query, query.once], 'value');
snapshot.forEach(function(child) {
console.log(child.key, child.val().username);
});
Initially, I was thinking the equalTo() query along with Firebase .indexOn the username.
However, what we really need is a substring like ECMAScript 6's String.prototype.startsWith() method:
.startsWith(inputValue);
So, The only way I see to do it with realtime DB is to get/fetch/.once it then process client side where you have more robust string matching capability. I guess the next question is how to pull/fetch only the username property of each user key.
To query based on the first character, you should get that character and pass it to the startAt() function:
const query = ref.orderByChild('username').startAt(action.searchText.charAt(0));

Categories