Lookup pipeline: `$match` local field `$in` array when from value is the array and local value is to be found

本小妞迷上赌 提交于 2020-01-16 09:06:06

问题


I have 2 collections. I want to do an aggregate on Collection A where it matches an ID. From there, I want to lookup from Collection B where the matched ID from Collection A (local field) is in the array of Collection B (foreign field).

So basically:

Collection A:

{
    _id: ObjectId('<id>')
},
{
    _id: ObjectId('<id>')
},
{
    _id: ObjectId('<id>')
}

Collection B:

{
    _id: ObjectId('<id>'),
    related: ['<id>', '<id>', '<id>', '<id>']
},
{
    _id: ObjectId('<id>'),
    related: ['<id>', '<id>', '<id>', '<id>']
},
{
    _id: ObjectId('<id>'),
    related: ['<id>', '<id>', '<id>', '<id>']
}

Query:

db.collection_a.aggregate({
    [$match: {_id: ObjectId('<id>')}],
    // other $lookups...
    [
        $lookup: {
            as: 'collection_b',
            from: 'collection_b',
            let: {id: '$_id'},
            pipeline: [
                {
                    $match: {
                        $expr: {$in: ['$related', '$$id']}
                    }
                }
                // sorts, projections, etc...
            ]
        }
    ]
    // sorts, projections, etc...
});

Desired Result:

[
    {
        _id: ObjectId('<id>'),
        collection_b: [
            {
                _id: ObjectId('<id>'),
                related: ['<id>', '<id>', '<id>', '<id>']
            },
            {
                _id: ObjectId('<id>'),
                related: ['<id>', '<id>', '<id>', '<id>']
            }
        ]
    },
]

Result:

$in requires an array as a second argument, found: objectId

Now, I know that switching this up and looking up Collection A on Collection B is possible, however, this is not an option in this instance (Collection A should still be queried, even if it is not present in any document in Collection B). Preferable to keep this to one query.

Any help is greatly appreciated.


回答1:


Can you please try this :

db.collection_a.aggregate(
[{ $match: { _id: ObjectId(' ') } },
// other $lookups...
{
    $lookup: {
        as: 'collection_b',
        from: 'collection_b',
        let: { id: { $toString: '$_id' } },
        pipeline: [
            {
                $addFields: {
                    "related": {
                        "$cond": {
                            "if": {
                                "$ne": [{ "$type": "$related" }, "array"]
                            },
                            "then": [],
                            "else": "$related"
                        }
                    }
                }
            },
            {
                $match: {
                    $expr: { $in: ['$$id', '$related'] }
                }
            }
            // sorts, projections, etc...
        ]
    }
}
           // sorts, projections, etc...
]);

As it says $in takes an array as second parameter and a value you're searching for to be first parameter.



来源:https://stackoverflow.com/questions/57295616/lookup-pipeline-match-local-field-in-array-when-from-value-is-the-array-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!