Updating a specific doc in array in subdocument in MongoDb - node.js

I have a document user that have a schema as:
{
"_id" : ObjectId("57b2d706f61d04e8d99dd983"),
"addressesAsVendor" : [
{
"_id" : "V1",
"addressLine1" : "al1",
"addressLine2" : "al2",
"street" : "street",
"city" : "city",
"country" : "IN",
"pincode" : "490020",
"location" : {
"latitutde" : "lat1",
"longitude" : "lon1"
}
},
{
"_id" : "V2",
"addressLine1" : "al1",
"addressLine2" : "al2",
"street" : "street",
"city" : "city",
"country" : "IN",
"pincode" : "490020",
"location" : {
"latitutde" : "lat2",
"longitude" : "lon2"
}
}
]
}
Now let's suppose I want to update the V1 id of the addressesAsVendor array which is inside the user Id 57b2d706f61d04e8d99dd983 with the data:
{
"addressLine1" : "al1 new",
"addressLine2" : "al2 new",
"street" : "street new",
"city" : "city new",
"country" : "IN new",
"pincode" : "490020 new",
"location" : {
"latitutde" : "lat1 new",
"longitude" : "lon1 new"
}
}
So the new user doc will look like:
{
"_id" : ObjectId("57b2d706f61d04e8d99dd983"),
"addressesAsVendor" : [
{
"_id" : "V1",
"addressLine1" : "al1 new",
"addressLine2" : "al2 new",
"street" : "street new",
"city" : "city new",
"country" : "IN new",
"pincode" : "490020 new",
"location" : {
"latitutde" : "lat1 new",
"longitude" : "lon1 new"
}
},
{
"_id" : "V2",
"addressLine1" : "al1",
"addressLine2" : "al2",
"street" : "street",
"city" : "city",
"country" : "IN",
"pincode" : "490020",
"location" : {
"latitutde" : "lat2",
"longitude" : "lon2"
}
}
]
}
How this can be achieved in MongoDb and what's the best way of keeping multiple addresses, which can be easily shown in the Address page of the user and also minimum in load, I mean will be easy to access when required.
Please shed your views.
:)

You can do the update using the positional $ operator:
var data = {
"addressLine1" : "al1 new",
"addressLine2" : "al2 new",
"street" : "street new",
"city" : "city new",
"country" : "IN new",
"pincode" : "490020 new",
"location" : {
"latitutde" : "lat1 new",
"longitude" : "lon1 new"
}
};
collection.update(
{ "addressesAsVendor._id" : "V1" },
{ "$set": { "addressesAsVendor.$": data } },
function(err, result) {
if (err) return handleError(err);
console.log(result);
}
)
The positional operator in the above saves the index (0 in the case above) of the element from the array that matched the query. This means that if you knew the position of the element beforehand (which is nearly impossible in a real life case), you could just change the update statement to: { "$set": { "addressesAsVendor.0": data } }.
Since the positional $ operator acts as a placeholder for the first element that matches the query document, and the array field must appear as part of the query document hence the query { "addressesAsVendor._id" : "V1" } is essential to get the $ operator to work properly.
Please note that the positional $ operator (for now) updates the first relevant document ONLY, there is a JIRA ticket for this.
For your follow-up question which seeks to find the best way of keeping multiple addresses, which can be easily shown in the Address page of the user and also minimum in load:
Your current schema is a better approach than creating a separate collection of addresses since separate collections require more work i.e. finding a user + its addresses is two queries and requires extra work whereas the above schema embedded documents are easy and fast (single seek). There are no big differences for inserts and updates. So, separate collections are good if you need to select individual documents, need more control over querying, or have huge documents. Embedded documents are good when you want the entire document, the document with a $slice of the embedded addressesAsVendor, or with no addresses at all.
As a general rule, if you have a lot of "addresses" or if they are large, a separate collection might be best.
Smaller and/or fewer documents tend to be a natural fit for embedding.

You can use updateOne (MongoDB query) to update the document.
NodeJS equivalent is:-
collection.update(criteria, update[[, options], callback]);
Please change the object id accordingly.
db.address.updateOne({ "_id" : ObjectId("57c04425c400a6b59c9bc1ee"), "addressesAsVendor._id" : "V1" }, { $set: { "addressesAsVendor.$.addressLine1" : "al1 new",
"addressesAsVendor.$.addressLine2" : "al2 new",
"addressesAsVendor.$.street" : "street new",
"addressesAsVendor.$.city" : "city new",
"addressesAsVendor.$.country" : "IN new",
"addressesAsVendor.$.pincode" : "490020 new",
"addressesAsVendor.$.location" : {
"latitutde" : "lat1 new",
"longitude" : "lon1 new"
}
} });

Related

MongoDB Manual and DBRef referencing using node js

I have two case ,first case: where in my key has reference to the same collection ,is this correct way to reference ?,if yes ! how to de-ref/link in node js ?,if not how to reference fom the same collection
{
"_id" : ObjectId("53402597d852426020000002"),
"address" : {
"$ref" : "home_adress"
},
"contact" : "987654321",
"dob" : "01-01-1991",
"name" : "Tom Benzamin",
"Post_address" : {
"$ref" : "home_adress"
},
"home_adress":"Street 1, NY"}
case two: reference to a different collection(DBRefs),How to detect the reference and send the second query to fetch the referenced value ?
{
"_id" : ObjectId("53402597d852426020000002"),
"address" : {
"$ref" : "address_home",
"$id" : ObjectId("534009e4d852427820000002"),
"$db" : "ref"
},
"contact" : "987654321",
"dob" : "01-01-1991",
"name" : "Tom Benzamin"}
{
"_id" : ObjectId("534009e4d852427820000002"),
"building" : "22 A, Indiana Apt",
"pincode" : 123456,
"city" : "Los Angeles",
"state" : "California"}

mongodb descendent sorting by a numeric field getting sorted randomly (node.js)

I have a mongo database running in cmd.
There is a collection named usercollection.
And there is also some documents which I'm getting by typing in mongo shell:
db.usercollection.find().sort({score: -1}).pretty()
Output:
{
"_id" : ObjectId("57501b2d7ef17cd8c1bd63bc"),
"name" : "QWERTY",
"score" : "100",
"link" : "http://qwerty.com"
}
{
"_id" : ObjectId("5750199819433f80da88c847"),
"name" : "Adam Sandler",
"score" : "222",
"link" : "http://sandler.com"
}
{
"_id" : ObjectId("57501af57ef17cd8c1bd63bb"),
"name" : "gfhfghfghguy",
"score" : "5",
"link" : "http://dsad.com"
}
{
"_id" : ObjectId("57501bb47ef17cd8c1bd63bd"),
"name" : "Test name",
"score" : "50",
"link" : "http://fdsfds.cpm"
}
{
"_id" : ObjectId("574f4a9dab868fdc896d11b4"),
"name" : "Rich Man",
"score" : "500",
"link" : "http://jikl.me"
}
{
"_id" : ObjectId("574f50f1fbd256888ffa248d"),
"name" : "lfgfgff",
"score" : "9",
"link" : "http://oh.com"
}
{
"_id" : ObjectId("574f5324fbd256888ffa248e"),
"name" : "test name",
"score" : "9",
"link" : "http://dsad.com"
}
The problem is that I'm trying to sort these documents from one with highest score to one with lowest score and it's output is completely random(
I'm displaying that documents on the website using node.js and the result is the same as in the console.
Try with :
db.usercollection.find().sort({score: 'desc'}).pretty()

finding the parent document id based on the sub document _id of array field

Hyy , I have a collection where comments related to the blog are stored in multiple document as shown below.
[
{
"_id" : ObjectId("565f0f5d77f0c7bd11bbadd8"),
"blog_id" : ObjectId("56587befdb7224110f007233"),
"comments" : [
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "pradip is bhole baba",
"_id" : ObjectId("565f0f5d77f0c7bd11bbadd9"),
"dt" : ISODate("2015-12-02T15:33:49.578Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "honkog pokhara... he he ha ha",
"_id" : ObjectId("565f1034fd07cbfc1129db0b"),
"dt" : ISODate("2015-12-02T15:37:24.581Z")
}
],
"record_count" : 2,
"__v" : 0
}
{
"_id" : ObjectId("565efa37635f09900d21a339"),
"blog_id" : ObjectId("56587befdb7224110f007233"),
"comments" : [
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "wat a nice car wow",
"_id" : ObjectId("565efa37635f09900d21a33a"),
"dt" : ISODate("2015-12-02T14:03:35.289Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "love is life budikhola ma dives",
"_id" : ObjectId("565efa76635f09900d21a33b"),
"dt" : ISODate("2015-12-02T14:04:38.661Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "bholi ajaya ko bihe",
"_id" : ObjectId("565efaa0635f09900d21a33c"),
"dt" : ISODate("2015-12-02T14:05:20.847Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "manish is nice",
"_id" : ObjectId("565efb17635f09900d21a33d"),
"dt" : ISODate("2015-12-02T14:07:19.704Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "niroj is cool",
"_id" : ObjectId("565efd53c22dddc80e8f461c"),
"dt" : ISODate("2015-12-02T14:16:51.730Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "ramesh is cool",
"_id" : ObjectId("565f0d376d82e24c11f6c0d1"),
"dt" : ISODate("2015-12-02T15:24:39.010Z")
}
],
"record_count" : 6,
"__v" : 0
}
]
Suppose user wants to update his comment; for this I would have the comments _id now my problem is that how can I detect in which document the comment exist based of the comment _id value of comments array field.
suppose I have a comment "_id" : "565f0f5d77f0c7bd11bbadd9" (first element of first document)
then the result should give the parent document _id:"565f0f5d77f0c7bd11bbadd8" (first document id)
How can I do this..
Thank you in advance
if possible, then please update your schema.
Suppose you have collection of Blog. Then your code will be :
Blog.find({'comments._id' : '565f0f5d77f0c7bd11bbadd9'}).exec(function(err,blog){
if(!err && blog){
console.log("Blog id :"+blog._id);
}
else{
console.log("Dont get your blog");
}
});
if your comments are directly stored on the blog document you could go with an aggregate method to collect the comment across all documents. note that this seems to work when you don't have any object references to be populated.
asuming all documents are based on a blog Schema and that you wish to recieve the id of the comment:
Blog.aggregate(
[{'$match':{'comments':{'$elemMatch:{'_id':'565f0f5d77f0c7bd11bbadd9'}}}},
{'$project':{comments:'$_id', user_id:1}},
{'$unwind':'$comments'}
{'$group':{_id:'$comments'}}
]).exec(function(err, results){
if(results){
console.log(results);
}
});
I hope this is somewhat what you're looking for, you might find the following read usefull
elementMatch and aggregation from the mongoDB docs.
cheers!
The site recommended this old question to me as being Related to another I was looking at. Looks like a sufficient answer wasn't ever given, so I'll provide it for any future readers.
The requested behavior here is very straightforward to achieve with a basic find() query:
db.collection.find(
{ "comments._id": ObjectId("565f0f5d77f0c7bd11bbadd9") },
{ _id: 1 }
)
Here we are filtering the documents based on the values of the _id fields embedded in the comments array. Then for the matching document(s) we are applying a projection to just retrieve the _id field of the "parent document" (e.g. the document that was matched). If the _ids for the comments are unique then there will only ever be a maximum of a single matching document. Sample playground demonstration is here.
A more complicated aggregation would have only been necessary here if the intent was to always provide the _id value of the first document associated with a given blog_id but that does not appear to be the case here.

Mongo: Group, push and sort

I have a mongodb collection data as per below;I want to group by EmployeedID( i.e 0001) and then sort(by age)
{
"_id" : ObjectId("54d0512191a4da7736e9db43"),
"EmployeeID" : "0001",
"Speciality" : "xxx",
"Code" : "P",
"Age" : 8
}
/* 1 */
{
"_id" : ObjectId("54d0512191a4da7736e9db44"),
"EmployeeID" : "0002",
"Speciality" : "yyyyy",
"Code" : "P",
"Age" : 6
}
/* 2 */
{
"_id" : ObjectId("54d0512191a4da7736e9db45"),
"EmployeeID" : "0001",
"Speciality" : "zzz",
"Code" : "P",
"Age" : 5
}
I know I can group using the following way.
collection.aggregate([
{$match:{"EmployeeId":0001}},
{$group:{"_id":"$EmployeeID",
"speciality":{$push:"$Speciality"},
"Code":{$push:"$Code"},
"Age":{$push:"$Age"}}}
])
But how can I using $sort here? SO my result can be something like below;
[{ "EmployeeID" : "0001",
"speciality" : [ "zzz","xxx"],
"Code" :[ "P","P"],
"Age" : [5,8]
}]
You can sort the document prior to the grouping stage:
collection.aggregate([
{$sort: {_id: -1}},
{$match:{"EmployeeId":0001}},
{$group:{"_id":"$EmployeeID",
"speciality":{$push:"$Speciality"},
"Code":{$push:"$Code"},
"Age":{$push:"$Age"}}}
])
Sorting prior to grouping may exceed mongo's memory when dealing with large collections. Fortunately, you can set allowDiskUse to true to allow mongo to write temporary files.

Upsert embedded object in mongoDB

Given this Person collection:
{
"_id" : ObjectId("4f8e95a718bcv9c74da1e6511a"),
"name" : "John",
"hobbies" : [{
"id" : 001,
"name" : "reading",
"location" : "home"
},{
"id" : 002,
"name" : "sport",
"location" : "outside"
}]
}
and these new/edited Hobby objects:
{
"name" : "walking",
"location" : "outside"
}
and
{
"id" : 001,
"name" : "reading",
"location" : "outside"
}
If I know the Person that I want to manage, what is be the best way to upsert embedded objects?
Currently my approach is to find the Person object, make the required modifications to it in my code, and then save it back to the DB. This works. But I'd like to simplify and reduce the number of round trips to the database.

Resources