Change name in collection with multiple documents in MongoDB and Meteor - mongodb

If I have a collection with multiple documents for one person like:
{ FullName: "Jane Doe", Camp: "may12", Week1: "0", Week2: "1", Week3: "0" }
{ FullName: "Jane Doe", Camp: "may13", Week1: "0", Week2: "0", Week3: "1" }
{ FullName: "Jane Doe", Camp: "may14", Week1: "0", Week2: "1", Week3: "0" }
and I need to update her name to "Jane Smith", I get her name from a Session:
var nameAddressFullName = Session.get('clientName');
Get all the documents with her name in put them into an array:
var documentNameAddressP = Programs.find({ FullName: nameAddressFullName}).fetch();
Then try to update all the names (I need to update based on _id values only), I'd need something like:
Programs.update({ _id: {$in: {documentNameAddressP._id}}, {$set: {FullName: nameChange}}); //????
We need to update all Jane Doe's documents to the full name Jane Smith keeping all the rest of the properties intact.

If you do this update via a method call to server then you can bulk update all the documents there in one go with {multi: true} in your update query.
From the client you can easily iterate over the cursor:
Programs.find({ FullName: nameAddressFullName}).forEach(function(doc){
Programs.update({ _id: doc._id },{ $set: { FullName: nameChange }});
});

You can select element to update in update query:
Programs.update({FullName: nameAddressFullName},{$set: {FullName: nameChange}})
https://docs.mongodb.org/manual/reference/operator/update/set/

Related

The best method of relations between two collection

I am trying to create a parent-child relationship between two collections in MongoDB.
The first way:
// users document
{
"_id": "63e422adcb1ee8e6ffa4f4c7",
"name": "Joe"
}
// address documents
{
"_id": "77775554441ee8e6ffa4f4c7",
parent_id: "63e422adcb1ee8e6ffa4f4c7", // reference to users document
street: "123 Fake Street",
city: "Faketon",
state: "MA",
zip: "12345"
},
{
"_id": "55545adcb1ee8e6ffa4f4c7a",
parent_id: "63e422adcb1ee8e6ffa4f4c7", // reference to users document
street: "123 Fake Street",
city: "Faketon",
state: "MA",
zip: "12345"
}
Here have the users collection will have a unique "_id" objectid, and the address collection will have a "_id" objectid and a "parent_id" field that references the parent "_id".
The second way
// users document
{
"_id": "63e422adcb1ee8e6ffa4f4c7",
"name": "Joe",
[
"77775554441ee8e6ffa4f4c7", // reference to address document
"55545adcb1ee8e6ffa4f4c7a" // reference to address document
]
}
// address documents
{
"_id": "77775554441ee8e6ffa4f4c7",
street: "123 Fake Street",
city: "Faketon",
state: "MA",
zip: "12345"
},
{
"_id": "55545adcb1ee8e6ffa4f4c7a",
street: "123 Fake Street",
city: "Faketon",
state: "MA",
zip: "12345"
}
Here, the first method mirrored the users collection the _id of the address collection
Which is better for performance, This is not a discussion, but I really have a problem that the child collection contains more than 10 million and I was thinking of distributing the data to the parent.
Assuming that the parent_id field and the unnamed child array are indexed, the performance of reads will be about the same for both.
The difference in writes would be while addresses the first way permits just inserting the new addresses, while the second way would also require updating the user document.

Update a nested field with an unknown index and without affecting other entries

I have a collection with a layout that looks something like this:
student1 = {
"First_Name": "John",
"Last_Name": "Doe",
"Courses": [
{
"Course_Id": 123,
"Course_Name": "Computer Science",
"Has_Chosen_Modules": false
},
{
"Course_Id": 284,
"Course_Name": "Mathematics",
"Has_Chosen_Modules": false
}
]
};
I also have the following update query:
db.Collection_Student.update(
{
$and: [
{First_Name: "John"},
{Last_Name: "Doe"}
]
},
{
$set : { "Courses.0.Has_Chosen_Modules" : true }
}
);
This code will currently update the Computer Science Has_Chosen_Modules value to true since the index is hardcoded. However, what if I wanted to update the value of Has_Chosen_Modules via the Course_Id instead (as the course might not necessarily be at the same index every time)? How would I achieve this without it affecting the other courses that a given student is taking?
You can select any item in the sub array of your document by targeting any property in the sub array of your document by using dot .
You can easily achieve this by the following query.
db.Collection_Student.update(
{
First_Name: "John",
Last_Name: "Doe",
'Courses.Course_Id': 123
},
{
$set : { "Courses.$.Has_Chosen_Modules" : true }
}
);
Conditions in search filter are by default treated as $and operator, so you don't need to specifically write $and for this simple query.

MongoDB: bulk create or update

I have an array of data that I want to insert in my database:
[
{
"id":"816307",
"email": "john.doe#test.com",
"firstName": "John",
"lastName": "Doe"
},
{
"id":"391650",
"email": "mary#williams",
"firstName": "Mary",
"lastName": "Williams"
},
{
"id":"183751",
"email": "paul.smith#test.com",
"firstName": "Paul",
"lastName": "Smith"
},
]
I know that I can use the .create method from mongoose to insert all the data.
However, in the data, I need to be able to have a combination of new values and existing values. For example, if a user with id 816307 (John Doe) already exists but have a different email it should update the value and at the same time if a user with id 391650 (Mary Williams) does not exist it should create it.
The id field cannot be updated.
It seems like the best method to use is currently updateMany and to use the upsert option to insert new elements at the same time .updateMany().
But, how to do to reference the id? I cannot use $eq and hardcode anything here, I would like that the document automatically finds the proper item by its id and update it if it exists, otherwise, create it.
Since each object has it's own filter & update, then you might not be able to do it using .updateMany(), instead you can use MongoDB's .bulkWrite(), with which you could do things in one DB call, internally MongoDB would do multiple write ops.
Try below code :
let input = [
{
id: "816307",
email: "john.doe#test.com",
firstName: "John",
lastName: "Doe",
},
{
id: "391650",
email: "mary#williams",
firstName: "Mary",
lastName: "Williams",
},
{
id: "183751",
email: "paul.smith#test.com",
firstName: "Paul",
lastName: "Smith",
},
];
let bulkArr = [];
input.forEach((each) => {
bulkArr.push({
updateOne: {
filter: each.id,
update: {
$set: {
email: each.email,
firstName: each.firstName,
lastName: each.lastName,
},
},
upsert: true,
},
});
});
db.collection.bulkWrite(bulkArr)

How to filter in mongodb dynamically?

I am creating app that can filter data dynamically.
If i select "John", "US", and leave the sex as blank it will return no result because the query will search a sex that is blank. I can't figure out how can i dynamically filter that in the mongodb.
ex:
var fName="John",
fCountry="US",
fSex="";
db.users.find({ $and[ {sex: fSex}, {first_name: fName}, {country: fCountry} ]})
That query will return none.
I want the code to return a answer like this if i select "John", "US":
{"_id": <object>, "first_name": "John", "sex": "Male", "country": "US"}
users:
{"_id": <object>, "first_name": "John", "sex": "Male", "country": "US"},
{"_id": <object>, "first_name": "Rex", "sex": "Male", "country": "Mexico"},
{"_id": <object>, "first_name": "Jane", "sex": "Female", "country": "Canada"}
Thank You in advance!, btw i am new to mongo
Edited
You can build the query object instead of assuming it's going to looks like a specific structure.
You can add whatever checks you'd like.
var fName="John",
fCountry="US",
fSex="";
var query = { $and: [] };
if (fName !== "") { query.$and.push({name: fName}); }
if (fCountry !== "") { query.$and.push({country: fCountry}); }
if (fSex !== "") { query.$and.push({sex: fSex}); }
db.users.find(query);
Update:
As per #semicolon's comment, the $and here is unnecessary as mongo, by default, will "and" different fields together. A simpler solution reads:
var query = {};
...
query.name = fName; // et cetera.
I'll add that it may become necessary to use the key $and and other operators when building more elaborate queries.

List all values existing of a property?

Assume I have a Student collection:
{
name: "ABC",
age: 10,
address {
city: "CITY1",
state: "STATE",
}
}
{
name: "DEF",
age: 11,
address {
city: "CITY2",
state: "STATE",
}
}
{
name: "ABC",
age: 12,
address {
city: "CITY1",
state: "STATE",
}
}
Can I get the list of all unique City values from the list? For example, with the above 3 documents, I would like to get the list {"CITY1", "CITY2"}
I was just getting started with MongoDB from Relational Database, so this is a little confused for me, since I needed another Address table for it and I can just use SELECT DISTINCT to get what I want.
MongoDB has a similar db.collection.distinct() command.
To access elements in the address subdocument you need to use dot notation, so the complete query would be:
db.Student.distinct("address.city")
Some helpful documentation links to help you make the translation from SQL queries:
SQL to MongoDB Mapping Chart
SQL to Aggregation Mapping Chart
Just for notes, there is already distinct as mentioned, but for a more conventional response, use aggregate:
db.Student.aggregate([
{"$unwind": "$address" }},
{"$group": { "_id": "$address.city" }},
{"$project": { "_id": 0, "city" : "$_id" }}
])
Long winded compared to distinct, but it depends on what your eyes want.