I have two main Schema in my project, Store, and User.
User collection as displayed in MongoDB Compass is the following :
_id : ObjectId("**5e830006c4cec2586875124b**")
hearts : Array
storeID : Array
email : "test#test.com"
name : "My name is Test"
photo : "fa75fa97-c5d8-4e63-a9ee-38441774a26e.jpeg"
slugAuthor : "my-name-is-test"
description : "My description is Test"
hash : "b841b82dcffdd0d517b5010d9ff2047ab447751a4e6dd573f9d55af..."
salt : "2bb0f785b134af11d7ca08d4086801fd880626498fbcf106c0df9a66"
__v : 0
Store collection as displayed in MongoDB Compass is the following :
_id : ObjectId("5e830050c4cec2586875124c")
tags : Array
name : "My activity is Test"
description : "My description us Test"
participants : 1
duree : 1
date : 2220-02-22T21:02:00.000+00:00
author : ObjectId("**5e830006c4cec2586875124b**")
created : 2020-03-31T08:33:20.234+00:00
slug : "my-activity-is-test"
__v : 0
What I need :
When I display the user information, I also want to search every Store he has created.
As you can see, the User id is found in the Store collection (author: ObjectId).
I need to display those information (User + list of stores that belongs to the User) when I hit the route http://..../store/my-name-is-test/5e830006c4cec2586875124b. In my route, I need to display as a slug the "slugAuthor" and the "author: ObjectId". (this is already managed).
What I have already tried (using .populate()) :
In my Store Schema :
author: {
type: mongoose.Schema.ObjectId,
ref: 'User',
}
In my User Schema :
listStores: [{
type: mongoose.Schema.ObjectId,
ref: 'Store'}],
In my controller:
exports.myProfil = async (req, res) => {
const user = await User.findOne({slugAuthor: req.params.slugAuthor}).populate('listStores')
res.render('my-profil', {user});
};
It gives me access to the following data :
{
"hearts": [],
"listStores": [],
"_id": "5e830006c4cec2586875124b",
"email": "test#test.com",
"name": "My name is Test",
"photo": "fa75fa97-c5d8-4e63-a9ee-38441774a26e.jpeg",
"slugAuthor": "my-name-is-test",
"description": "My description is Test",
"__v": 0
}
As you can see, "listStores" array is empty but I need it to be filled with every stores created by this user.
Would you please be kind enough to help me out here,
Many thanks
You can use aggregation for that. Take a look at the lookup
$lookup:
{
from: 'Store',
localField: _id, // the _id of the user
foreignField: author,
as: "listStores" // this might be something else
}
In this case instead of find you have to use User.aggregate
Hope this helps!
Related
I have created a collection say users, example documents like given below
[{
"name" : "John",
"code" : "B7"
},
{
"name" : "Sara",
"code" : "F7"
}]
I have created one index on field "name"
db.users.createIndex(
{ name: 1 },
{
collation: {locale: "en", strength: 1},
unique: true
}
)
I want to prevent duplicate case insensitive data for name field for example it will not allow entry for name "jOhn" or "jOHn" like that.
It's working but when I'm inserting data in mongodb is giving error messages
Inserted data given below
db.users.insert([{ "name" : "JoHn", "code" : "B9" }])
Error message given below
{
"message" : "WriteError({'code':11000,'index':0,'errmsg':'E11000 duplicate key error collection: digital_data_delivery.users index: name_1 dup key: { : \\';E7C\\' }','op':{'name':'JoHn','code':'B9','_id':'5b4836a458abe34b442a9811'}})",
"stack" : "script:1:10"
}
Some junk characters are coming here "E7C" I want to know what is this
I want to update a comment in a post. I first retrieve the post document which looks like this.
{
"_id" : ObjectId("5aac169c229f0136296407d4"),
"title" : "First Node.js App",
"body" : "testing 123",
"status" : "public",
"user" : "John Doe",
"date" : ISODate("2017-12-21T18:30:09.779Z"),
"comments" : [
{
"commentBody" : "This is awesome! ",
"commentUser" : ObjectId("5a3bfd5a9e65351f9c18ba18"),
"_id" : ObjectId("5a3c02379e65351f9c18ba1a"),
"commentDate" : ISODate("2017-12-21T18:49:27.620Z")
},
{
"commentBody" : "This is second comment.",
"commentUser" : ObjectId("5a3bfd5a9e65351f9c18gt19"),
"_id" : ObjectId("5a3c02379e65351f9c18ba1b"),
"commentDate" : ISODate("2017-12-21T18:49:27.620Z")
}
],
"allowComments" : true
}
Let say I want to update comment with "_id" ObjectId("5a3c02379e65351f9c18ba1a").
I've tried the following without luck.
const post = await Post.findById(req.body.postID);
await post.update({'comments._id' : req.body.commentID},{$set : {
'comments.$.commentBody': req.body.comment
}
});
This gave me the following error:
MongoError: cannot use the part (comments of comments._id) to traverse the element
Any suggestion would be greatly appreciated. Thanks in advance!
You can try something like this::
Post.findOneAndUpdate(
{ "_id": req.body.postID, "comments._id": req.body.commentID },
{
"$set": {
'comments.$.commentBody': req.body.comment
}
},
function(err,doc) {
}
);
I'm not sure about how to implement this in node.js but here is the Mongo query:
db.sample.aggregate([
{$match:{"comments.commentUser":ObjectId("5a3bfd5a9e65351f9c18ba19")}},
{$redact:{
$cond:{
if:{$or:[{$eq:["$commentUser",ObjectId("5a3bfd5a9e65351f9c18ba19")]},
{$not:"$commentUser"}]},
then:"$$DESCEND",
else:"$$PRUNE"
}
}},
{$addFields:{comments:{$map:{
input:"$comments",
as:"comment",
in:{"commentBody":"test comment", "commentUser" : "$$comment.commentUser", "_id" :"$$comment._id", "commentDate" :"$$comment.commentDate"}
}}
}},
{$out:"sample"}
])
Restricted the document such that only particular user id comments are displayed. After that, added comments with updated comment. Finally replacing the original content within aggregation without update query(note that collection will get replaced if you run the query). I didnt test this extensively, but working for small data set in my local. However, you might need to add some tweaks to this query and then check how u can add same query to node.js
This question already has answers here:
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 5 years ago.
I'm very new to using Mongo and I have a collection that looks like this
{
"_id" : "5e7a39ed-941a-4e07-af0b-df8764820206",
"title" : "Test Title Task",
"taskBody" : "This is a test task body",
"comments" : [
{
"_id" : "57b51a73-f585-4e80-ad51-107da707efd6",
"poster" : "Jack Black",
"comment" : "This is a comment"
},
{
"_id" : "4ea314f3-3671-4568-b938-d8a1477ac681",
"poster" : "Joe Blow",
"comment" : "Another comment"
},
{
"_id" : "c5f1a0e6-2fb9-429e-9931-8634f42fc143",
"poster" : "Mike Hall",
"comment" : " And yet Another comment"
}
]
}
And I'm trying to get one of the comment elements by passing the ID like this:
getCommentById(id) {
return tasks().then((taskCollection) => {
return taskCollection.find({ "comments._id": id }).toArray().then((commentQuery) => {
if (!commentQuery) throw "Comment not found";
return commentQuery;
});
});
}
However, it seems to be returning everything in the comments collection and not just one comment that I'm passing in the id for. How can I get it to return just the comment that I'm passing the id for?
This is what the debug window shows me
Array(1) [Object]
Object {_id: "5e7a39ed-941a-4e07-af0b-df8764820206", title: "Test Title Task", taskBody: "This is a test task body", …}
Array(3) [Object, Object, Object, …]
0: Object {_id: "57b51a73-f585-4e80-ad51-107da707efd6", poster: "Jack Black", comment: "Comment text 2"}
1: Object {_id: "4ea314f3-3671-4568-b938-d8a1477ac681", poster: "Joe Blow", comment: "Another comment"}
2: Object {_id: "c5f1a0e6-2fb9-429e-9931-8634f42fc143", poster: "Joe Blow", comment: "Another comment"}
What I'm expecting to get returned is just:
{
"_id" : "57b51a73-f585-4e80-ad51-107da707efd6",
"poster" : "Jack Black",
"comment" : "This is a comment"
}
Assuming "57b51a73-f585-4e80-ad51-107da707efd6" is the passed in ID. Any help would be appreciated.
You are querying sub array correctly. But your assumption is wrong. While you are querying with a specific sub document of an array field, a find query will still return a list of actual documents. You execute find on collection not just on an array field of a single document.
What you can do with mongoDB is this: you can exclude or include fields for your select queries. So you does not read unnecessary fields from mongoDB and it improves performance. You can learn more about this here
So for your question; while you just want to read a sub document in an array field, you have to use $ operator too. You can find more information here
Your query should look like this:
db.collection.find({ "_id": "some id", "comments._id": "some id"}, {"comments.$": 1, "_id": 0})
But again remember: This query will still return a list(or one collection if you use findOne) of your actual document, not a list of comment. Returned json will look like this:
{
"comments": [
{
"_id" : "57b51a73-f585-4e80-ad51-107da707efd6",
"poster" : "Jack Black",
"comment" : "This is a comment"
}
]
}
Note: If you really want just a comment with structure in your question. You can use aggregation and play the structure of json before return.
taskCollection.find({ "comments": {$elemMatch: { _id: 'your value here '}}})
This should work for you.
In my project Node and Mongo project, i'm using mongoose for my modelling.
I'm trying to perform a lookup on a nested document.
I have a thread object, with an array of "post" objects as one of its properties. One of the properties of this nested "post" object, is a user_id, the person who posted.
I've tried to lookup the user_id(ie - localfield: thread.post.user_id, from users, foreignfield: _id) but the shell keeps returning nothing.
Can anybody suggest an amendment to what i've tried below:
db.threads.aggregate([
{ "$match": { "posts._id": ObjectId("abcdef") } },
{ "$sort": { "dateAdded": -1 } },
{ "$limit": 15 },
{ "$lookup": {"localField": "posts.user_id","from": "users","foreignField": "_id","as": "userinfo"} },
{ "$unwind": "$userinfo" },
{ "$project":{"dateAdded":1,"userinfo.name":1,"userinfo.username":1}}
]);
And a sample of the records in my collections
db.threads.find({}) returns...
{
"_id" : ObjectId("78910"),
"dateAdded" : ISODate("2017-08-18T16:44:23Z"),
"title" : "Thread Zero",
"posts" : [ {
"_id" : ObjectId("abcdef"),
"user_id" : ObjectId("12345"),
"postText" : "good evening",
"dateAdded" : "2017-8-18 17:44:34" } ],
"__v" : 0
}
db.users.find({}) returns...
Sample user object
{
"_id" : ObjectId("12345"), "name" : "James Free",
"name" : "Al Isonwunderland",
"password" : "$2a$10$ILpitvg1.o8X8GnaSaoG4ulnuNWrFTUfhQDA8CdihbHPjBrB8NaVm",
"username" : "muppet",
"__v" : 0
}
So from this, I would like to return the name property from the "user" object for each of the posts on the thread.
What i've written is an attempt to get the user's name ad username for one specific post, I would assume retrieving the user name and name for all comments is to leave the $match parameter blank, allowing it to return a list of posts along with the user's name/username
Can anyone confirm this?
I swapped out ObjectId for a uuid property as ObjectId is messy to deal with(the Mongo shell's .find() function returns as ObjectId("5998a2a81762e90ce9f55d92"), then when reading from database it's just the alphanumeric("5998a2a81762e90ce9f55d92") returns and then inputting that alphanumeric into the shell to test commands always returns null)
The following solved my problem,
db.threads.aggregate([
{$match: {uuid: 'de36dd72-238b-47b0-b363-3fbfa1f2743e'}},
{$unwind:"$posts"},
{$lookup: {
from: 'users',
localField: 'posts.user_uuid',
foreignField: 'uuid',
as: 'userInfo'}}
]);
This MongoDB $lookup on nested document
proved useful.
Hope this helps someone else along the way
I have a collection data which has around 300k entries and its document looks like
{
"_id" : ObjectId("5xxx85"),
"user_id" : "1",
"name" : "test",
"user_private" : "0"
}
now i want to update all the documents in this collection and new document will look like
{
"_id" : ObjectId("5xxx85"),
"rid" : "1",
"user_name" : "test",
"is_private" : "private",
"is_moderator" : "true",
"amount" : "11111"
}
i.e i need to add new fields, update field names and check if user_private = 0 then put is_private as private or else put is_private as not_private.
I am a bit new so I am not able to get how can i do this efficiently as entries are around 300k.
Please suggest some ways, pseudo code will be really helpful
To update a document a filter criteria. Check pseudo code below and follow link to read more.
You'll need to have an existing value for user_private
db.messages.updateMany([
{ "user_private" : 0 }, // filter.
{ $set: {
"user_private" : "private",
"is_moderator" : "true"
}
}, // update.
{
upsert: true
}
]);
upserts - Creates a new document if no documents match the filter or Updates documents that match the filter based on the filter and update parameters provided.