MongoDB – Getting Limited Data from $unwind

aggregatemongodb

I have a chats collection which given down below

{
    "_id" : ObjectId("5a44e6545818041cde24aac9"),
    "messages" : [ 
        {
            "createdAt" : ISODate("2017-12-23T07:46:29.201Z"),
            "message" : "Hii",
            "userId" : "000000"
        }, 
        {
            "createdAt" : ISODate("2017-12-23T12:46:29.201Z"),
            "message" : "Bye gtg ttyl",
            "userId" : "111111"
        }, 
        {
            "createdAt" : ISODate("2017-12-24T07:46:29.201Z"),
            "message" : "Bye Take Care",
            "userId" : "000000"
        }
    ],
    "createdAt" : ISODate("2017-10-23T07:46:29.201Z"),
    "users" : [ 
        {
            "facebookId" : "0000000",
            "unread" : 0
        }, 
        {
            "facebookId" : "111111",
            "unread" : 0
        }
    ]
}

When I do this following query in nodejs

chats.aggregate( [ { $unwind : "$messages" },{ $unwind : "$users" } ])

I get an array which is something like this in which unwind opens my array something like this

[
    {
        "_id": "5a44e6545818041cde24aac9",
        "messages": {
            "createdAt": "2017-12-23T07:46:29.201Z",
            "message": "Hii",
            "userId": "000000"
        },
        "createdAt": "2017-10-23T07:46:29.201Z",
        "users": {
            "facebookId": "0000000",
            "unread": 0
        }
    },
    {
        "_id": "5a44e6545818041cde24aac9",
        "messages": {
            "createdAt": "2017-12-23T07:46:29.201Z",
            "message": "Hii",
            "userId": "000000"
        },
        "createdAt": "2017-10-23T07:46:29.201Z",
        "users": {
            "facebookId": "111111",
            "unread": 0
        },
    }, //And so on.
] 

But can I only get the objects after unwind where messages.userId !== users.facebookId

something like the following object directly from MongoDB when i fetch data

[
    {
        "_id": "5a44e6545818041cde24aac9",
        "messages": {
            "createdAt": "2017-12-23T07:46:29.201Z",
            "message": "Hii",
            "userId": "000000"
        },
        "createdAt": "2017-10-23T07:46:29.201Z",
        "users": {
            "facebookId": "111111",
            "unread": 0
        },
    },{
        "_id": "5a44e6545818041cde24aac9",
        "messages": {
            "createdAt": "2017-12-23T12:46:29.201Z",
            "message": "Bye gtg ttyl",
            "userId": "111111"
        },
        "createdAt": "2017-10-23T07:46:29.201Z",
        "users": {
            "facebookId": "0000000",
            "unread": 0
        }
    }, {
        "_id": "5a44e6545818041cde24aac9",
        "messages": {
            "createdAt": "2017-12-24T07:46:29.201Z",
            "message": "Bye Take Care",
            "userId": "000000"
        },
        "createdAt": "2017-10-23T07:46:29.201Z",
        "users": {
            "facebookId": "111111",
            "unread": 0
        }
    }
]

I tried this but the output is same :/

chats.aggregate( [ { $unwind : "$messages" },{ $unwind : "$users" },{$match:{ 'messages.userId' :{ $ne: '$users.facebookId'}}}]).exec(function(err, data) { res.send(data); });

Best Answer

As per MongoDB BOL $unwind Deconstructs an array field from the input documents to output a document for each element. Each output document is the input document with the value of the array field replaced by the element.

The $unwind stage has the following prototype form:

{ $unwind: <field path> }

To specify a field path, prefix the field name with a dollar sign $ and enclose in quotes.

Behaviors

$unwind has the following behaviors:
  1. If a value in the field specified by the field path is not an array, db.collection.aggregate() generates an error.
  2. If you specify a path for a field that does not exist in an input document, the pipeline ignores the input document and will not output documents for that input document.
  3. If the array holds an empty array ([]) in an input document, the pipeline ignores the input document and will not output documents for that input document.

For example

Consider an inventory with the following document:

> db.inventoty.insert({"_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] })
WriteResult({ "nInserted" : 1 })
> db.inventory.find().pretty()
> db.inventory.insert({"_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] })
WriteResult({ "nInserted" : 1 })
> db.inventory.find().pretty()
{ "_id" : 1, "item" : "ABC1", "sizes" : [ "S", "M", "L" ] }
> db.inventory.aggregate( [ { $unwind : "$sizes" } ] )
{ "_id" : 1, "item" : "ABC1", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "L" }

Each document is identical to the input document except for the value of the sizes field which now holds a value from the original sizes array.