Vinicius Raupp
Vinicius Raupp

Reputation: 23

Mongodb aggregate unexpected array result - Needs to return an object from $lookup instead of an array

I'm joining two collections, but the result of trends is an array, each item always has only one trend, how do I remove the trend inside array?

'Items' collection:

{
 "itemid" : "370",
 "name" : "A"
},
{
"itemid" : "378",
 "name" : "B"
}

'Trends' collection

{
 "itemid" : "370",
 "max" : "715705",
},
{
 "itemid" : "378",
 "max" : "35346",
}

Command executed:

db.items.aggregate([
{
    $lookup: {
            from: "trends",
            localField: "itemid",
            foreignField: "itemid",
            as: "trend"
            }
    }
])

Result:

{
 "itemid" : "370",
 "name" : "A",
 "trend" : [       // unexpected array, the result is always a single 'trend'
        {
          "itemid" : "370",
          "max" : "715705",
        }
    ]
},
...

Expected:

{
 "itemid" : "370",
 "name" : "A",
 "trend" : {      // yeah, without array          
             "itemid" : "370",
             "max" : "715705",                    
            }
},
...

Upvotes: 2

Views: 778

Answers (2)

whoami - fakeFaceTrueSoul
whoami - fakeFaceTrueSoul

Reputation: 17935

It's not an unexpected result, as $lookup would result in retrieving all matched documents into an array i.e; trend will be an array in your case. It's for a reason, Assume if you're joining collection A with collection B & documents in collection A might multiple matching documents in collection B then all those documents from collection B are pulled into an array of that relative document of collection A in your case trend field. Here if you wanted to get object inside it you need to do one of these ::

db.items.aggregate([
{
    $lookup: {
            from: "trends",
            localField: "itemid",
            foreignField: "itemid",
            as: "trend"
            }
    },
    { $addFields: { trend: {$arrayElemAt : ["$trend", 0] } } } // This stage is going re-write trend field with first object from trend array created by $lookup stage.
])

(Or)

db.items.aggregate([
{
    $lookup: {
            from: "trends",
            localField: "itemid",
            foreignField: "itemid",
            as: "trend"
            }
    },
     { $unwind: { path: "$trend", preserveNullAndEmptyArrays: true } } 
])

Note : When you use $unwind you need to be cautious that you need to use preserveNullAndEmptyArrays option as if trend is an [] - which means no match found in collection B, then $unwind is going to remove all collection A documents with trend :[] in the final aggregation result.

Upvotes: 2

Raul Sanchez Reyes
Raul Sanchez Reyes

Reputation: 151

You can do it with $unwind pipeline stage

db.items.aggregate([
{
    $lookup: {
            from: "trends",
            localField: "itemid",
            foreignField: "itemid",
            as: "trend"
            }
    },
    $unwind:"$trend"
])

Upvotes: 3

Related Questions