Mongodb aggregation to return data from multiple collections - mongodb

I have a database with comments and users. I'm attempting to run an aggregation to get data returned in a certain format with populated nested documents (see below)
Some comments are replies to other comments, which is tracked by the reply_to property in the comment model. There can be many replies for the same comment.
What I'm attempting to do is return comment documents in an array, with all of the replies in a replies property in each comment, along with some user data (display_name).
Here is sample data:
comments
{
"_id": "63acacb169f733cf45f22e51",
"user": "63acacb169f733cf45f22e4f",
"body": "I love this recipe!",
"rating": 5,
"article_id": "Y4Iu0hIAACsAohcA",
"status": "Approved",
"createdAt": "2022-12-28T20:53:05.761Z",
"updatedAt": "2022-12-28T20:55:05.837Z",
"__v": 0
},
{
"_id": "63acb0df4f4adc6e16001fe7",
"user": "636261acb4ce6745b38d8785",
"reply_to": "63acac8569f733cf45f22e49",
"article_id": "Y4Iu0hIAACsAohcA",
"status": "Trashed",
"createdAt": "2022-12-28T21:10:55.698Z",
"updatedAt": "2022-12-28T21:13:27.544Z",
"__v": 0
},
{
"_id": "63acb16d4f4adc6e16001fef",
"user": "636261acb4ce6745b38d8785",
"body": "I Love it too!",
"reply_to": "63acac8569f733cf45f22e49",
"article_id": "Y4Iu0hIAACsAohcA",
"status": "Approved",
"createdAt": "2022-12-28T21:13:17.665Z",
"updatedAt": "2022-12-28T21:13:29.199Z",
"__v": 0
},
users
{
"_id": "63ac944ac2faa2dd59f6a492",
"display_name": "Jane Doe",
"email": "dfasfasdf#example.com",
"__v": 0
},
{
"_id": "63acacb169f733cf45f22e4f",
"display_name": "Juice Guy",
"email": "juiceguy#example.com",
"__v": 0
}
Here's an example of how I want the data returned when I query for comments by article_id, so I can display all comments and replies on the page for the user.
{
"_id": "63acacb169f733cf45f22e51",
"user": {
"display_name": "John Doe",
},
"body": "I love this recipe!",
"rating": 5,
"createdAt": "2022-12-28T20:53:05.761Z",
"updatedAt": "2022-12-28T20:55:05.837Z",
"replies": [
{
"body": "I love this too!",
"user": {
"display_name": "Juice Guy"
},
"createdAt": "2022-12-28T20:53:05.761Z",
"updatedAt": "2022-12-28T20:55:05.837Z"
}
]
}
]
I've been playing with $group and $lookup but with the nested documents I can't get all the data I want in one aggregation. Can someone help?

To get these in a single document, you would need to:
$match for documents that do not have a reply_to field (top-level comments)
$lookup from comments, matching local _id with foreign reply_to
$unwind the replies
$lookup from users matching local user with remote _id
$lookup from users matching local replies.user with remote _id
$project to select/remove fields as desred
$group by _id, retaining all of the top level fields, and $push the replies back into an array
$replaceRoot/$project to finalize the shape of the returned document

Related

How to fetch records from mongoDB on the basis of duplicate data in multiple fields

The requirement is to fetch the document with some field having the same values in the particular collection..
For Example:
we have two documents below:
1. {
"_id": "finance100",
"status": "ACTIVE",
"customerId": "100",
"contactId": "contact_100",
"itemId": "profile_100",
"audit": {
"dateCreated": "2022-02-16T16:34:52.718539Z",
"dateModified": "2022-03-18T09:36:42.774271Z",
"createdBy": "41d38c187155427fa37c855a4d1868d1",
"modifiedBy": "41d38c187155427fa37c855a4d1868d1"
},
"location": "US"
}
2. {
"_id": "finance101",
"status": "ACTIVE",
"customerId": "100",
"contactId": "contact_100",
"itemId": "profile_100",
"audit": {
"dateCreated": "2022-02-16T16:34:52.718539Z",
"dateModified": "2022-03-18T09:36:42.774271Z",
"createdBy": "41d38c187155427fa37c855a4d1868d1",
"modifiedBy": "41d38c187155427fa37c855a4d1868d1"
},
"location": "US"
}
3. {
"_id": "finance101",
"status": "ACTIVE",
"customerId": "100",
"contactId": "contact_100",
"itemId": "profile_100",
"audit": {
"dateCreated": "2022-02-16T16:34:52.718539Z",
"dateModified": "2022-03-18T09:36:42.774271Z",
"createdBy": "41d38c187155427fa37c855a4d1868d1",
"modifiedBy": "41d38c187155427fa37c855a4d1868d1"
},
"location": "UK"
}
The following parameter should have the same values:
customerId
contactId
itemId
location
so, need the fetch those records, matching with these above parameters having the same values in all the documents.
So, it should fetch the first two records (1 and 2) because the values for customerId, contactId, itemId, and location is same in first two document and in 3rd document only the location value is different(so it will not be fetched).
Could you please share the appropriate mongo query to work for this. I tried aggeration but it did not work. Thanks in advance.
Need the fetch those records, matching with these above parameters having the same values in all the documents.

Aggregate and match multiple subdocuments in mongoDB

So I have the following document structure:
{
"id": 0,
"users": [
{
"name": "bob",
"id": 1000
},
{
"name": "sally",
"id": 2000
}
],
"comments": [
{
"commentor_index": 0,
"comment": "foo",
"emoji": "smile"
},
{
"commentor_index": 0,
"comment": "bar",
"emoji": "heart"
},
{
"commentor_index": 1,
"comment": "zee",
"emoji": "heart"
}
]
}
The comments have the users index in the array.
I would like to be able to get how many comments each user id left across all documents.
I have gotten so far to realize I need to unwind both users and comments with includeArrayIndex for users, but I have trouble rejoining them.

mongoDB Compass distinct query renders no results

I've been trying to write a distinct query against my mongoDB collection housed in Atlas.
I wanted to get a list of all the distinct values captured within the "Section" attribute under its "MetaData" parent attribute. According to the mongoDB documentation the syntax to get an array of distinct values is the following syntax:
{ distinct: "<collection>", key: "<field>" }
My sample collection called "simple" holds the following documents
[{
"_id": "527c61082241f813c09c722c",
"MetaData": {
"Type": "BlogPost",
"Author": "author1",
"Section": "section1"
},
"Title": "title 1",
"Description": "..."
},
{
"_id": "527c61082241f813c09c7050",
"MetaData": {
"Type": "BlogPost",
"Author": "author1",
"Section": "section1"
},
"Title": "title 2",
"Description": "..."
},
{
"_id": "527c61082241f813c09c7042",
"MetaData": {
"Type": "BlogPost",
"Author": "author1",
"Section": "section2"
},
"Title": "title 3",
"Description": "..."
}
]
yet when I execute the following filter query in Compass or Atlas's - no results are returned ???
{distinct: 'simple',key: 'MetaData.Section'}
I was expecting an array holding "section1" and "section2"
Can someone tell what I'm doing incorrectly please
Thanks
You need to use aggregation framework for compass to get distinct values
{
$group:{
"_id": null,
"sections": { $addToSet: "$MetaData.Section"}
}
}

MongoDB query: aggregate with "findOne"

I'm trying to make a query on MongoDB 3.4 where I add a field for one specific element of an array. Example of the object:
{
"_id": 1,
"people": [
{
"name": "Jhon Smith",
"age": "30",
"state": "NY"
},{
"name": "Clint Mercer",
"age": "50",
"state": "NY"
},{
"name": "Walter Smith",
"age": "40",
"state": "WI"
}
]
}
And I want to make a query where I'll add to this document an attribute with the first person with "Smith" in it's name. Example:
{
"_id": 1,
"people": [
{
"name": "Jhon Smith",
"age": "30",
"state": "NY"
},{
"name": "Clint Mercer",
"age": "50",
"state": "NY"
},{
"name": "Walter Smith",
"age": "40",
"state": "WI"
}
],
"firstSmith": {
"name": "Jhon Smith",
"age": "30",
"state": "NY"
}
}
I already have the _id of the document I want, but I can't understand how to make a query like this. I'm trying using aggregate with "$match" for the id and "$addFields" after, but I can't make a query that works for this field to find exactly what I want. I think it would be similar to the "findOne" query, but I can't find anything that works on "$addFields".
Obs: I DON'T want the "firstSmith" to be an array with just one "people" inside, I want it as is in the example.
I'd appreciate some help with this one.
$match - to filter the relevant document
$filter with $regexMatch - to filter people array by the name property
arrayElemAt - to get only the first element of above array
$addFields - to add new field with value from above result
db.collection.aggregate([
{
"$match": {
"_id": 1
}
},
{
"$addFields": {
"firstSmith": {
"$arrayElemAt": [
{
"$filter": {
"input": "$people",
"cond": {
"$regexMatch": {
"input": "$$this.name",
"regex": "Smith"
}
}
}
},
0
]
}
}
}
])
Working example

update multiple documents of specific field values based on _Id

i have the two sample documents as :
[
{
"_id": "605b2fcb526b8b609ef97eaa",
"comments": "",
"name": "",
"user_name": ""
},
{
"_id": "605b3034asubc2bed542f88f",
"comments": "",
"name": "",
"user_name": ""
}
]
and the updated data for these two documents for key comment i have as :
[
{
"_id": "605b2fcb526b8b609ef97eaa",
"comments": "test one",
"name": "",
"user_name": ""
},
{
"_id": "605b3034asubc2bed542f88f",
"comments": "test two",
"name": "",
"user_name": ""
}
]
Here I am currently trying using a loop by ID and update the respective comment value using update
May i know how could i use update_many in this scenario ?
Any guiding links or a solution is much appreciated TIA
There is no way you can update different values to the same field in different documents in a single query to Mongo (update_many or otherwise).
You need to use a loop or you can do a Bulk.