Related
Report table sample data
{
"_id" : ObjectId("614415f4a6566a001623b622"),
"record" : [
{
"dateTime" : ISODate("2021-09-17T04:13:39.465Z"),
"status" : "time-in",
"month" : 9,
"day" : 17,
"year" : 2021,
"time" : 1631852019465.0,
"date" : ISODate("2021-09-17T00:00:00.000Z"),
},
{
"dateTime" : ISODate("2021-09-17T04:14:01.182Z"),
"status" : "time-out",
"month" : 9,
"day" : 17,
"year" : 2021,
"time" : 1631852041182.0,
"date" : ISODate("2021-09-17T00:00:00.000Z"),
}
],
"uid" : ObjectId("614415b0a6566a001623b80b"),
"date" : ISODate("2021-09-17T00:00:00.000Z"),
"status" : "time-out",
"createdAt" : ISODate("2021-09-17T04:13:40.102Z"),
"updatedAt" : ISODate("2021-09-17T04:14:01.831Z"),
"__v" : 0
}
Users table sample data
{
"_id" : ObjectId("615c0f6db30aff375cd05ac1"),
"displayName" : "test test",
"firstName" : "test",
"lastName" : "test",
"email" : "test#gmail.com",
"brand" : "Jollibee",
"phone" : "+632312312312312",
"role" : 1,
"isVerified" : true,
"isArchived" : false,
"createdAt" : ISODate("2021-10-05T08:40:13.208Z"),
"updatedAt" : ISODate("2021-10-05T08:40:13.208Z"),
"__v" : 0
}
I have a data like this
db.getCollection('users').aggregate([
{
"$match": { brand: "Jollibee" }
},
{
$lookup: {
from: "orders",
let: { id: 'id' },
pipeline: [
{
$match: {
date: { $gte: ISODate("2020-11-01"), $lt: ISODate("2021-11-31") },
}
}
],
as: "orders",
},
},
{
$project: {
"_id": 1,
"name": 1,
"orders": 1
}
}
])
when I'm using this aggregation I'm getting all the data inserted per user.
What I want to happen is that. I will only get the data that belong to the user and not all the data of all users.
Added the sample documents for each collection
You are not comparing the userIds of both collections. You should add that on your $match. Playground
db.users.aggregate([
{
"$match": {
brand: "Jollibee"
}
},
{
$lookup: {
from: "orders",
let: {
id: "$_id"
},
pipeline: [
{
$match: {
date: {
$gte: ISODate("2020-11-01"),
$lt: ISODate("2021-11-30")
},
$expr: {
$eq: [
"$uid",
"$$id"
]
}
}
}
],
as: "orders",
},
},
{
$project: {
"_id": 1,
"name": 1,
"orders": 1
}
}
])
I want to aggregate unread messages count per member in a conversation group and seems my aggregation pipeline is working correctly, but, I don't know how to achieve the following results.
Please check the example.
Thread documents
/* 1 */
{
"_id" : ObjectId("60d4efa6a95f446051f31492"),
"latestMessage" : "Voluptatem eos officiis optio dolor est et.",
"type" : "FEED",
"users" : [
{
"_id" : ObjectId("60d4efa6a95f446051f31491"),
"displayName" : "Monique Connelly II"
},
{
"_id" : ObjectId("60d4efa6a95f446051f31490"),
"displayName" : "Ivory Jacobson DDS"
},
{
"_id" : ObjectId("60d4efa6a95f446051f3148f"),
"displayName" : "Ron Weimann"
}
],
"createdBy" : "60d4efa6a95f446051f3148f",
"createdAt" : ISODate("2021-06-24T20:48:38.537Z"),
"modifiedAt" : ISODate("2021-06-24T20:48:38.620Z"),
}
/* 2 */
{
"_id" : ObjectId("60d4efa6a95f446051f31493"),
"type" : "CONVERSATION",
"users" : [
{
"_id" : ObjectId("60d4efa6a95f446051f31491"),
"displayName" : "Monique Connelly II"
},
{
"_id" : ObjectId("60d4efa6a95f446051f31490"),
"displayName" : "Ivory Jacobson DDS"
},
{
"_id" : ObjectId("60d4efa6a95f446051f3148f"),
"displayName" : "Ron Weimann"
}
],
"createdBy" : "60d4efa6a95f446051f3148f",
"createdAt" : ISODate("2021-06-24T20:48:38.569Z"),
"modifiedAt" : ISODate("2021-06-24T20:48:38.569Z"),
}
Message documents
/* 1 */
{
"_id" : ObjectId("60d4efa6a95f446051f31494"),
"content" : "Itaque rerum facere neque fuga aspernatur dolorum.",
"deleted" : false,
"threadId" : ObjectId("60d4efa6a95f446051f31492"),
"type" : "TEXT",
"thread" : {
"$ref" : "threads",
"$id" : ObjectId("60d4efa6a95f446051f31492")
},
"readBy" : [
ObjectId("60d4efa6a95f446051f3148f")
],
"attributes" : [],
"createdBy" : "60d4efa6a95f446051f3148f",
"createdAt" : ISODate("2021-06-24T20:48:38.598Z"),
"modifiedAt" : ISODate("2021-06-24T20:48:38.598Z"),
}
/* 2 */
{
"_id" : ObjectId("60d4efa6a95f446051f31495"),
"content" : "Nisi suscipit iste magni voluptatem.",
"deleted" : false,
"threadId" : ObjectId("60d4efa6a95f446051f31492"),
"type" : "TEXT",
"thread" : {
"$ref" : "threads",
"$id" : ObjectId("60d4efa6a95f446051f31492")
},
"readBy" : [
ObjectId("60d4efa6a95f446051f3148f")
],
"attributes" : [],
"createdBy" : "60d4efa6a95f446051f3148f",
"createdAt" : ISODate("2021-06-24T20:48:38.610Z"),
"modifiedAt" : ISODate("2021-06-24T20:48:38.610Z"),
}
and more...
My aggregation pipeline
db.threads.aggregate([
{ "$lookup": { "from": "messages", "localField": "_id", "foreignField": "threadId", "as": "message"}},
{ "$unwind": "$message" },
{ "$unwind": "$users" },
{ "$unwind": "$message.readBy" },
{ "$group": {
"_id": {
"user_id": "$users._id",
"thread_id": "$_id",
},
"unread_messages": {
"$sum": {
"$cond": [
{ "$ne": [ "$users._id", "$message.readBy" ] },
1,
0
]
}
}
}},
// { "$replaceRoot": { "newRoot": { "$mergeObjects": ["$_id", { "count": "$unread_messages" }]} } }
])
Aggregation results
{
"_id" : {
"user_id" : ObjectId("60d4efa6a95f446051f31491"),
"thread_id" : ObjectId("60d4efa6a95f446051f31492")
},
"unread_messages" : 4.0
},
{
"_id" : {
"user_id" : ObjectId("60d4efa6a95f446051f3148f"),
"thread_id" : ObjectId("60d4efa6a95f446051f31492")
},
"unread_messages" : 4.0
},
{
"_id" : {
"user_id" : ObjectId("60d4efa6a95f446051f31490"),
"thread_id" : ObjectId("60d4efa6a95f446051f31492")
},
"unread_messages" : 4.0
}
Results are partially OK, but, I want to keep my original structure of a document and copy aggregation results accordingly to the thread id back to the original document
I would be very grateful if you help me with the aggregation pipeline
Expected results
{
"_id": ObjectId("60d4efa6a95f446051f31492"),
"latestMessage": "Voluptatem eos officiis optio dolor est et.",
"type": "LISTING",
"users": [{
"_id": ObjectId("60d4efa6a95f446051f31491"),
"displayName": "Monique Connelly II"
},
{
"_id": ObjectId("60d4efa6a95f446051f31490"),
"displayName": "Ivory Jacobson DDS"
},
{
"_id": ObjectId("60d4efa6a95f446051f3148f"),
"displayName": "Ron Weimann"
}
],
"createdBy": "60d4efa6a95f446051f3148f",
"createdAt": ISODate("2021-06-24T20:48:38.537Z"),
"modifiedAt": ISODate("2021-06-24T20:48:38.620Z"),
"message": [...],
"stats": [{
"_id": {
"user_id": ObjectId("60d4efa6a95f446051f31491"),
"thread_id": ObjectId("60d4efa6a95f446051f31492")
},
"unread_messages": 4.0
},
{
"_id": {
"user_id": ObjectId("60d4efa6a95f446051f3148f"),
"thread_id": ObjectId("60d4efa6a95f446051f31492")
},
"unread_messages": 4.0
},
{
"_id": {
"user_id": ObjectId("60d4efa6a95f446051f31490"),
"thread_id": ObjectId("60d4efa6a95f446051f31492")
},
"unread_messages": 4.0
}
]
}
I post a solution that works perfectly for my case with $first + $replateRoot operations.
Final results have different ids as not in the first post that is because I re-created documents
db.threads.aggregate([
{ "$lookup": { "from": "messages", "localField": "_id", "foreignField": "threadId", "as": "message"}},
{ "$unwind": "$message" },
{ "$unwind": "$users" },
{ "$unwind": "$message.readBy" },
{ "$group": {
"_id": {
"user_id": "$users._id",
"thread_id": "$_id",
},
"thread": {
"$first": "$$ROOT"
},
"unread_messages": {
"$sum": {
"$cond": [
{ "$ne": [ "$users._id", "$message.readBy" ] },
1,
0
]
}
}
}},
{ "$group": {
"_id": "$_id.thread_id",
"thread": { "$first": "$thread" },
"stats": {
"$push": {
"userId": "$_id.user_id",
"unreadMessages": "$unread_messages"
}
}
}},
{ "$replaceRoot": { "newRoot": { "$mergeObjects": ["$thread", { stats: "$stats" }]} } }
])
Final results
/* 1 */
{
"_id" : ObjectId("60d574e242e59a48b886c586"),
"latestMessage" : "Molestias quo quod occaecati exercitationem veniam eaque.",
"type" : "LISTING",
"users" : {
"_id" : ObjectId("60d574e242e59a48b886c584"),
"displayName" : "Meggan Vandervort"
},
"unreadMessages" : NumberLong(0),
"createdBy" : "60d574e242e59a48b886c582",
"createdAt" : ISODate("2021-06-25T06:17:06.547Z"),
"modifiedAt" : ISODate("2021-06-25T06:17:06.617Z")
"message" : {
"_id" : ObjectId("60d574e242e59a48b886c58d"),
"content" : "Velit dolores vel.",
"deleted" : false,
"threadId" : ObjectId("60d574e242e59a48b886c586"),
"type" : "TEXT",
"thread" : {
"$ref" : "threads",
"$id" : ObjectId("60d574e242e59a48b886c586")
},
"readBy" : ObjectId("60d574e242e59a48b886c582"),
"attributes" : [],
"createdBy" : "60d574e242e59a48b886c582",
"createdAt" : ISODate("2021-06-25T06:17:06.595Z"),
"modifiedAt" : ISODate("2021-06-25T06:17:06.595Z")
},
"stats" : [
{
"userId" : ObjectId("60d574e242e59a48b886c584"),
"unreadessages" : 6.0
},
{
"userId" : ObjectId("60d574e242e59a48b886c583"),
"unreadessages" : 6.0
},
{
"userId" : ObjectId("60d574e242e59a48b886c582"),
"unreadessages" : 6.0
}
]
}
and more...
I'm new to mongodb. I need to know how it is possible to query item for set to the value with aggregate
Data
[
{
"_id" : "11111",
"parent_id" : "99",
"name" : "AAAA"
},
{
"_id" : "11112",
"parent_id" : "99",
"name" : "BBBB"
},
{
"_id" : "11113",
"parent_id" : "100",
"name" : "CCCC"
},
{
"_id" : "11114",
"parent_id" : "99",
"name" : "DDDD"
}
]
mongoshell
Assume $check is false
db.getCollection('test').aggregate(
[
{
"$group": {
"_id": "$id",
//...,
"item": {
"$last": {
"$cond": [
{"$eq": ["$check", true]},
"YES",
* * ANSWER **,
}
]
}
},
}
]
)
So i need the result for item is all the name contain with same parent_id as string of array
Expect result
[
{
"_id" : "11111",
"parent_id" : "99",
"name" : "AAAA",
"item" : ["AAAA","BBBB","DDDD"]
},
{
"_id" : "11112",
"parent_id" : "99",
"name" : "BBBB",
"item" : ["AAAA","BBBB","DDDD"]
},
{
"_id" : "11113",
"parent_id" : "100",
"name" : "CCCC",
"item" : ["CCCC"]
},
{
"_id" : "11114",
"parent_id" : "99",
"name" : "DDDD",
"item" : ["AAAA","BBBB","DDDD"]
}
]
Try this..
Sample live demo
db.collection.aggregate([
{
"$group": {
"_id": "$parent_id",
"item": {
"$push": "$name"
},
"data": {
"$push": {
"_id": "$_id",
"name": "$name"
}
}
}
},
{
"$unwind": "$data"
},
{
"$project": {
"_id": "$data._id",
"parent_id": "$_id",
"name": "$data.name",
"item": 1
}
}
])
I have a question regarding the $group argument of MongoDb aggregations. My data structure looks as follows:
My "Event" collection contains this single document:
{
"_id": ObjectId("mongodbobjectid..."),
"name": "Some Event",
"attendeeContainer": {
"min": 0,
"max": 10,
"attendees": [
{
"type": 1,
"status": 2,
"contact": ObjectId("mongodbobjectidHEX1")
},
{
"type": 7,
"status": 4,
"contact": ObjectId("mongodbobjectidHEX2")
}
]
}
}
My "Contact" collection contains these documents:
{
"_id": ObjectId("mongodbobjectidHEX1"),
"name": "John Doe",
"age": 35
},
{
"_id": ObjectId("mongodbobjectidHEX2"),
"name": "Peter Pan",
"age": 60
}
What I want to do is perform an aggregate query on the "Event" collection and get the following result with full "contact" data:
{
"_id": ObjectId("mongodbobjectid..."),
"name": "Some Event",
"attendeeContainer": {
"min": 0,
"max": 10,
"attendees": [
{
"type": 1,
"status": 2,
"contact": {
"_id": ObjectId("mongodbobjectidHEX1"),
"name": "John Doe",
"age": 35
}
},
{
"type": 7,
"status": 4,
"contact": {
"_id": ObjectId("mongodbobjectidHEX2"),
"name": "Peter Pan",
"age": 60
}
}
]
}
}
The arguments I am using right now look as follows (shortened version):
"$unwind" : "$attendeeContainer.attendees",
"$lookup" : { "from" : "contactinfo", "localField" : "attendeeContainer.attendees.contact","foreignField" : "_id", "as" : "contactInfo" },
"$unwind" : "$contactInfo",
"$group" : { "_id": "$_id",
"name": { "$first" : "$name" },
...
"contact": { "$push": { "contact": "$contactInfo"} }
}
However, this leads to the "contact" array being on "Event" level (because of the grouping) instead of one document of the array being at each "attendeeContainer.attendees". How can I push the "contact" array to be at "attendeeContainer.attendees"? (as shown in the desired output above)
I tried things like:
"attendeeContainer.attendees.contact": { "$push": { "contact": "$contactInfo"} }
But mongodb apparently does not allow "." at $group stage.
Try running the following aggregation pipeline, the key is using a final $project pipeline to create the attendeeContainer subdocument:
db.event.aggregate([
{ "$unwind": "$attendeeContainer.attendees" },
{
"$lookup" : {
"from" : "contactinfo",
"localField" : "attendeeContainer.attendees.contact",
"foreignField" : "_id",
"as" : "attendeeContainer.attendees.contactInfo"
}
},
{ "$unwind": "$attendeeContainer.attendees.contactInfo" },
{
"$group": {
"_id" : "$_id",
"name": { "$first": "$name" },
"min" : { "$first": "$attendeeContainer.min" },
"max" : { "$first": "$attendeeContainer.max" },
"attendees": { "$push": "$attendeeContainer.attendees" }
}
},
{
"$project": {
"name": 1,
"attendeeContainer.min": "$min",
"attendeeContainer.max": "$min",
"attendeeContainer.attendees": "$attendees"
}
}
])
Debugging Tips
Debugging the pipeline at the 4th stage, you would get the result
db.event.aggregate([
{ "$unwind": "$attendeeContainer.attendees" },
{
"$lookup" : {
"from" : "contactinfo",
"localField" : "attendeeContainer.attendees.contact",
"foreignField" : "_id",
"as" : "attendeeContainer.attendees.contactInfo"
}
},
{ "$unwind": "$attendeeContainer.attendees.contactInfo" },
{
"$group": {
"_id": "$_id",
"name": { "$first": "$name" },
"min" : { "$first": "$attendeeContainer.min" },
"max" : { "$first": "$attendeeContainer.max" },
"attendees": { "$push": "$attendeeContainer.attendees" }
}
}/*,
{
"$project": {
"name": 1,
"attendeeContainer.min": "$min",
"attendeeContainer.max": "$min",
"attendeeContainer.attendees": "$attendees"
}
}*/
])
Pipeline result
{
"_id" : ObjectId("582c789282a9183adc0b53f5"),
"name" : "Some Event",
"min" : 0,
"max" : 10,
"attendees" : [
{
"type" : 1,
"status" : 2,
"contact" : ObjectId("582c787682a9183adc0b53f3"),
"contactInfo" : {
"_id" : ObjectId("582c787682a9183adc0b53f3"),
"name" : "John Doe",
"age" : 35
}
},
{
"type" : 7,
"status" : 4,
"contact" : ObjectId("582c787682a9183adc0b53f4"),
"contactInfo" : {
"_id" : ObjectId("582c787682a9183adc0b53f4"),
"name" : "Peter Pan",
"age" : 60
}
}
]
}
and the final $project pipeline will give you the desired result:
db.event.aggregate([
{ "$unwind": "$attendeeContainer.attendees" },
{
"$lookup" : {
"from" : "contactinfo",
"localField" : "attendeeContainer.attendees.contact",
"foreignField" : "_id",
"as" : "attendeeContainer.attendees.contactInfo"
}
},
{ "$unwind": "$attendeeContainer.attendees.contactInfo" },
{
"$group": {
"_id": "$_id",
"name": { "$first": "$name" },
"min" : { "$first": "$attendeeContainer.min" },
"max" : { "$first": "$attendeeContainer.max" },
"attendees": { "$push": "$attendeeContainer.attendees" }
}
},
{
"$project": {
"name": 1,
"attendeeContainer.min": "$min",
"attendeeContainer.max": "$min",
"attendeeContainer.attendees": "$attendees"
}
}/**/
])
Desired/Actual Output
{
"_id" : ObjectId("582c789282a9183adc0b53f5"),
"name" : "Some Event",
"attendeeContainer" : {
"min" : 0,
"max" : 10,
"attendees" : [
{
"type" : 1,
"status" : 2,
"contact" : ObjectId("582c787682a9183adc0b53f3"),
"contactInfo" : {
"_id" : ObjectId("582c787682a9183adc0b53f3"),
"name" : "John Doe",
"age" : 35
}
},
{
"type" : 7,
"status" : 4,
"contact" : ObjectId("582c787682a9183adc0b53f4"),
"contactInfo" : {
"_id" : ObjectId("582c787682a9183adc0b53f4"),
"name" : "Peter Pan",
"age" : 60
}
}
]
}
}
I have the following collection for messages:
{
"_id" : ObjectId("56214d5632001bae07a6e6b3"),
"sender_id" : 8,
"receiver_id" : 2,
"content" : "fdgfd",
"state" : 1,
"timestamp" : 1445023062899.0000000000000000
},
{
"_id" : ObjectId("56214d5c32001bae07a6e6b4"),
"sender_id" : 2,
"receiver_id" : 8,
"content" : "fasfa",
"state" : 1,
"timestamp" : 1445023068443.0000000000000000
},
{
"_id" : ObjectId("56214d8032001bae07a6e6b5"),
"sender_id" : 2,
"receiver_id" : 8,
"content" : "dfdsfds",
"state" : 1,
"timestamp" : 1445023104363.0000000000000000
},
{
"_id" : ObjectId("56214d8032001bae07a6e6b6"),
"sender_id" : 2,
"receiver_id" : 8,
"content" : "fdsf",
"state" : 1,
"timestamp" : 1445023104825.0000000000000000
},
{
"_id" : ObjectId("56214d8132001bae07a6e6b7"),
"sender_id" : 2,
"receiver_id" : 8,
"content" : "sfsdfs",
"state" : 1,
"timestamp" : 1445023105436.0000000000000000
},
{
"_id" : ObjectId("56214d8132001bae07a6e6b8"),
"sender_id" : 2,
"receiver_id" : 8,
"content" : "f",
"state" : 1,
"timestamp" : 1445023105963.0000000000000000
},
{
"_id" : ObjectId("56214d8432001bae07a6e6b9"),
"sender_id" : 2,
"receiver_id" : 8,
"content" : "qwqwqwq",
"state" : 1,
"timestamp" : 1445023108202.0000000000000000
},
{
"_id" : ObjectId("56214db032001bae07a6e6ba"),
"sender_id" : 9902,
"receiver_id" : 2,
"content" : "fsafa",
"state" : 1,
"timestamp" : 1445023152297.0000000000000000
}
I'm trying to get all unique users ids that had been messaging with user 2, along with the last content message. So the result should be:
[ { user: 8, lastContent: "qwqwqwq" }, { user: 9902, lastContent: "fsafa" } ]
By now, I have the following code:
db.getCollection('messenger').group({
keyf: function(doc) {
return { user: doc.user };
},
cond: {
$or : [
{ sender_id : 2 },
{ receiver_id : 2 }
]
},
reduce: function( curr, result ) {
result.user = (curr.sender_id == 2 ? curr.receiver_id : curr.sender_id);
result.content = curr.content;
},
initial: { } })
But I only get the last id. The result:
{
"0" : {
"user" : 9902.0000000000000000,
"content" : "fsafa"
} }
Can anyone help me with this?
You need to use the .aggregate() method. You need to reduce the size of documents in the pipeline using the $match operator which filter out all documents where the receiver_id is not equal to 2. After that you need to $sort your document by timestamp in descending order this will help us get the content of last message sent. Now comes the $group stage where you group your documents and use the $addToSet operator which returns array of distinct sender_id and distinct receiver_id and the $last operator to get the last message content. Now to get the user_ids we need union of distinct sender_id and receiver_id which we can get after $projection using the $setUnion operator.
db.messenger.aggregate([
{ "$match": {
"$or": [
{ "sender_id": 2 },
{ "receiver_id": 2 }
]
}},
{ "$sort": { "timestamp": 1 } },
{ "$group": {
"_id": null,
"receiver_id": {
"$addToSet": { "$receiver_id" }
},
"sender_id": {
"$addToSet": { "$sender_id" }
},
"lastContent": { "$last": "$content" }
}},
{ "$project": {
"_id": 0,
"lastContent": 1,
"user_ids": {
"$setUnion": [
"$sender_id",
"$receiver_id"
]
}
}}
])
Which returns:
{ "lastContent" : "fsafa", "user_ids" : [ 9902, 2, 8 ] }
Now if what you want is distinct user alongside their last content message with user 2 then here it is:
db.messenger.aggregate([
{ "$match": {
"$or": [
{ "sender_id": 2 },
{ "receiver_id": 2 }
]
}},
{ "$sort": { "timestamp": 1 } },
{ "$group": {
"_id": {
"sender": "$sender_id",
"receiver": "$receiver_id"
},
"lastContent": {
"$last": "$content"
},
"timestamp": { "$last": "$timestamp" },
"sender": { "$addToSet": "$sender_id" },
"receiver": { "$addToSet": "$receiver_id" }
}},
{ "$project": {
"_id": 0,
"user": {
"$setDifference": [
{ "$setUnion": [ "$sender", "$receiver" ] },
[ 2 ]
]
},
"lastContent": 1,
"timestamp": 1
}},
{ "$unwind": "$user" },
{ "$sort": { "timestamp": 1 } },
{ "$group": {
"_id": "$user",
"lastContent": { "$last": "$lastContent" }
} }
])
Which yields:
{ "_id" : 9902, "lastContent" : "fsafa" }
{ "_id" : 8, "lastContent" : "qwqwqwq" }