Search code examples
node.jsmongodbmongooseaggregate

Mongodb aggregation returns empty array even though data is there


Hello guys I have been working on a project where I am building a chat app

so I have a model for chatting like this

const chatSchema = new mongoose.Schema(
    {
        participants: [
            {
                type: mongoose.Schema.Types.ObjectId,
                ref: 'User',
            },
        ],
        messages: [
            {
                from: {
                    type: mongoose.Schema.Types.ObjectId,
                    ref: 'User',
                },
                message: String,
                date: {
                    type: Date,
                    default: Date.now,
                },
                delivered: [
                    {
                        type: mongoose.Schema.Types.ObjectId,
                        ref: 'User',
                    },
                ],
                seen: [
                    {
                        type: mongoose.Schema.Types.ObjectId,
                        ref: 'User',
                    },
                ],
            },
        ],
        isGroup: {
            type: Boolean,
            default: false,
        },
        groupName: {
            type: String,
        },
        admins: [
            {
                type: mongoose.Schema.Types.ObjectId,
                ref: 'User',
            },
        ],
    },
    { timestamps: true },
);

Now to get messages from this schema I am writing the following MongoDB aggregation query

const aggregateQuery: PipelineStage[] = [
            {
                $match: findQuery,
            },
            {
                $unwind: '$messages',
            },
            {
                $lookup: {
                    from: 'users',
                    localField: 'messages.from',
                    foreignField: '_id',
                    as: 'messages.from',
                    pipeline: [
                        {
                            $project: {
                                username: 1,
                                name: 1,
                                email: 1,
                            },
                        },
                    ],
                },
            },
            {
                $unwind: '$messages.from',
            },
            {
                $sort: {
                    'messages.date': -1,
                },
            },
            {
                $group: {
                    _id: '$_id',
                    'sortedMessages': { $push: '$messages' },
                    participants: { $first: '$participants' },
                    isGroup: { $first: '$isGroup' },
                    groupName: { $first: '$groupName' },
                    admins: { $first: '$admins' },
                },
            },
            {
                $project: {
                    messages: {
                        $reverseArray: {
                            $slice: ['$sortedMessages', skip, limit],
                        },
                    },
                    groupName: 1,
                    participants: 1,
                    isGroup: 1,
                    admins: 1,
                    count: {
                        $size: '$sortedMessages',
                    },
                },
            },
            {
                $lookup: {
                    from: 'users',
                    localField: 'participants',
                    foreignField: '_id',
                    as: 'sender',
                    pipeline: [
                        {
                            $match: {
                                _id: {
                                    $ne: new mongoose.Types.ObjectId(userId),
                                },
                            },
                        },
                        {
                            $limit: 1,
                        },
                        {
                            $project: {
                                username: 1,
                                name: 1,
                                email: 1,
                            },
                        },
                    ],
                },
            },
            {
                $unwind: '$sender',
            },
        ];

Now the problem is when an array of messages has some values because whenever I create a chat document I assign an empty array inside it like this [] so when hitting this query and If the array is empty then even though the match query finds the result comes as an empty array without any data

but if the message array has something in it then data comes as expected.

I can not figure out what I am doing wrong here.

the find query goes like this

const findQuery = {
    participants: {
       $in: [new mongoose.Types.ObjectId(req.user?._id)]

}

NOTE: I checked server times userId is there. 🙂

Here is a document without messages and with messages

with messages ⬇️

{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859f0"
  },
  "participants": [
    {
      "$oid": "62c9a0f5dfb6cf9c7fe859e1"
    },
    {
      "$oid": "62c9a0f5dfb6cf9c7fe859cf"
    }
  ],
  "messages": [
    {
      "from": {
        "$oid": "62c9a0f5dfb6cf9c7fe859e1"
      },
      "message": "Hi this is first message.",
      "delivered": [
        {
          "$oid": "62c9a0f5dfb6cf9c7fe859e1"
        }
      ],
      "seen": [
        {
          "$oid": "62c9a0f5dfb6cf9c7fe859e1"
        }
      ],
      "_id": {
        "$oid": "62c9a3464fe8c3886b2aed37"
      },
      "date": {
        "$date": {
          "$numberLong": "1657381702152"
        }
      }
    },
    {
      "from": {
        "$oid": "62c9a0f5dfb6cf9c7fe859e1"
      },
      "message": "Hi this is first message.",
      "delivered": [
        {
          "$oid": "62c9a0f5dfb6cf9c7fe859e1"
        }
      ],
      "seen": [
        {
          "$oid": "62c9a0f5dfb6cf9c7fe859e1"
        }
      ],
      "_id": {
        "$oid": "62c9a75495dedf71b6028b55"
      },
      "date": {
        "$date": {
          "$numberLong": "1657382740772"
        }
      }
    }
  ],
  "isGroup": false,
  "admins": [
    {
      "$oid": "62c9a0f5dfb6cf9c7fe859e1"
    },
    {
      "$oid": "62c9a0f5dfb6cf9c7fe859cf"
    }
  ],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109954"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657382740775"
    }
  },
  "__v": 2
}

And here is a document with an empty array ⬇️

{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859f2"
  },
  "participants": [
    {
      "$oid": "62c9a0f5dfb6cf9c7fe859e5"
    },
    {
      "$oid": "62c9a0f5dfb6cf9c7fe859e1"
    }
  ],
  "messages": [],
  "isGroup": false,
  "admins": [
    {
      "$oid": "62c9a0f5dfb6cf9c7fe859e5"
    },
    {
      "$oid": "62c9a0f5dfb6cf9c7fe859e1"
    }
  ],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109958"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109958"
    }
  },
  "__v": 0
}

In this scenario when I run the query document with data is coming but second document which has empty array is not getting returned.

This is my user's collection

[{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859c5"
  },
  "name": "Norberto Becker",
  "email": "corine5@gmail.com",
  "username": "juwan.king26",
  "password": "$2b$08$w5KowVsCZMt3rD9CrfJ3y.CXQf0EJ8x/akvaVw4qWN4O1LKtHr2ii",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109567"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109567"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859c9"
  },
  "name": "Austen Anderson",
  "email": "yesenia65@hotmail.com",
  "username": "ricky.gleichner1",
  "password": "$2b$08$0U6awlfx0lfm2.wW9xhI0.rmIVwSvbvta5RWBp2bkrOQbuhL45aO2",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109590"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109590"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859cb"
  },
  "name": "Karlie McLaughlin",
  "email": "estefania.nienow11@gmail.com",
  "username": "samantha96",
  "password": "$2b$08$HcaYbfcvKVkc2DRD4Ek2.OU2kSX.HxqjwUw44R2xkfAlAkxXwFinG",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109608"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109608"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859cd"
  },
  "name": "Joey McLaughlin",
  "email": "lucas26@hotmail.com",
  "username": "schuyler73",
  "password": "$2b$08$hJrocpP.ablQgF/LzklO7O4ofvgLd3k/xsqfhfwLgrNxqRG2CwtYm",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109626"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109626"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859cf"
  },
  "name": "Omer Mann",
  "email": "taylor44@hotmail.com",
  "username": "travis93",
  "password": "$2b$08$tXT4CetLDAql46VmC0wDKuXUt5TCkvYINf79MMuvBnh/TdTEtkDIS",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109646"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109646"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859d1"
  },
  "name": "Solon Jacobi",
  "email": "jammie1@yahoo.com",
  "username": "erna_quitzon",
  "password": "$2b$08$4DODzEWneeIOlT/8o4C5huOg/bD8cJft2F5JJnnCuqdw95yYMl9DC",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109665"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109665"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859d3"
  },
  "name": "Theresia Gutkowski",
  "email": "maudie9@yahoo.com",
  "username": "baby36",
  "password": "$2b$08$65YHzbE57lG7dBF1d/aErOiYbQq/YIPiL4clxJwkP7xViumQk8u0K",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109683"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109683"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859d5"
  },
  "name": "Neil Kshlerin",
  "email": "ayana53@yahoo.com",
  "username": "alek_braun",
  "password": "$2b$08$lUwqxHK27fe/Aq.LQWtjHOzDp86di3Zd7vj.0tqVkjGqJtzuf5/0.",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109703"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109703"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859d7"
  },
  "name": "Jackeline Gibson",
  "email": "calista4@yahoo.com",
  "username": "albertha.miller9",
  "password": "$2b$08$69Y6sJbGwIqCn5FkI5wzjuYpdWD.bN0kMWJIANI89NYhIbJhV5FBa",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109721"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109721"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859d9"
  },
  "name": "Luisa Koelpin",
  "email": "alexandra15@gmail.com",
  "username": "jimmie11",
  "password": "$2b$08$k7K0CmZAU3PAmcamQtdTZOAaFU.4cXW5IGCMKG2RIml2sSA1Enice",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109739"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109739"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859db"
  },
  "name": "Joel Cruickshank",
  "email": "rodrigo19@hotmail.com",
  "username": "eldridge.will20",
  "password": "$2b$08$30NCVEgtg0ydsD3.Azc9BOaetu5mxwybih9Y5Btu.IjMVjpbIPxiG",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109758"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109758"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859dd"
  },
  "name": "Nigel Walsh",
  "email": "emile_little@hotmail.com",
  "username": "emmie_hilpert",
  "password": "$2b$08$HsS37V8dy8T.uiZPkKqYnuL87QvXYPnms9ImV5DaYkxiNQ1ErRili",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109775"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109775"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859df"
  },
  "name": "Freddie Stehr",
  "email": "tony85@yahoo.com",
  "username": "flossie4",
  "password": "$2b$08$ypyqxVunL4cbaa8GlW0xiODupiK3tW9lvY1XDLWKqsU62ehJ7ma1S",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109799"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109799"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859e1"
  },
  "name": "Helene Treutel",
  "email": "eula.mclaughlin17@yahoo.com",
  "username": "alice32",
  "password": "$2b$08$TFwuY7YUN/ilF.xfwmtY8.5RZl1mT4scSAkw83SzRgE2jGA3ILiXq",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109821"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109821"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859e3"
  },
  "name": "Edythe Grimes",
  "email": "roma_mckenzie17@yahoo.com",
  "username": "malcolm.batz",
  "password": "$2b$08$KM6fCyJataf4UN7XrkYxY.HPatrfskqHJaFeGEyn4HU19/NkSzoiS",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109841"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109841"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859e5"
  },
  "name": "Deondre Ernser",
  "email": "verner_hudson@hotmail.com",
  "username": "suzanne14",
  "password": "$2b$08$dkhdUJp4RHraX/4cTq7XZOclpohxKgC5vaUPnXb0YmQzfkbx9lC0a",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109860"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109860"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859e7"
  },
  "name": "Roger Weber",
  "email": "mercedes.bayer@gmail.com",
  "username": "carrie_feil41",
  "password": "$2b$08$nReH9kaoLKmMX9Um9Ap/IeBhRRQZv5wSVjQaQvOnYlhEl9PSqreXq",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109877"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109877"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859e9"
  },
  "name": "Thelma Reinger",
  "email": "julie9@gmail.com",
  "username": "isaac19",
  "password": "$2b$08$Abbk7fC1BU1mtzQfwJA8ReYOkjCbBAadEd92rCUMLnw59hSOow3Ou",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109897"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109897"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859eb"
  },
  "name": "Hillard Beer",
  "email": "durward55@hotmail.com",
  "username": "blaze_weissnat",
  "password": "$2b$08$2MpQwgsvWLu52QZQNt1YT.Ih295gSG3WlWnWiamKVg67W3IylGENu",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109915"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109915"
    }
  },
  "__v": 0
},{
  "_id": {
    "$oid": "62c9a0f5dfb6cf9c7fe859ed"
  },
  "name": "Santino Klocko",
  "email": "jamil19@hotmail.com",
  "username": "bertrand_schinner73",
  "password": "$2b$08$KOKO2GU/QPIyWYLXqbVyE.FhizfrsLUZ/EOY.Zjd0mIoBX8Zdn36a",
  "isVerified": true,
  "friendRequests": [],
  "friends": [],
  "createdAt": {
    "$date": {
      "$numberLong": "1657381109931"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1657381109931"
    }
  },
  "__v": 0
}]

Solution

  • I'm not sure what is your expected results, but I think it is something close to the results if this simple query:

    db.orders.aggregate([
      {$lookup: {
          from: "users",
          localField: "participants",
          foreignField: "_id",
          as: "participants",
          pipeline: [{$project: {username: 1, name: 1, email: 1}}]
        }
      },
      {$set: {
          messages: {
            $map: {input: "$messages",
              in: {$mergeObjects: [
                  "$$this",
                  {from: {
                      $arrayElemAt: [
                        "$participants",
                        {$indexOfArray: ["$participants._id", "$$this.from"]}
                      ]
                    }
                  }
                ]
              }
            }
          }
        }
      }
    ])
    

    See how it works on the playground example