当外部字段是数组时的 MongoDB 查找

Mic*_*Cox 4 mongodb

我已经搜索了互联网和 StackOverflow,但我找不到答案,甚至找不到问题。

我有两个集合,reportsusers. 我希望我的查询返回所有报告并指示指定用户是否将该报告作为其数组中的收藏夹。

报告收集

{ _id: 1, name:"Report One"}
{ _id: 2, name:"Report Two"}
{ _id: 3, name:"Report Three"}
Run Code Online (Sandbox Code Playgroud)

用户收藏

{_id: 1, name:"Mike", favorites: [1,3]}
{_id: 2, name:"Tim", favorites: [2,3]}
Run Code Online (Sandbox Code Playgroud)

users.name="Mike" 的期望结果

{ _id: 1, name:"Report One", favorite: true}
{ _id: 2, name:"Report Two", favorite: false}
{ _id: 3, name:"Report Three", favorite: true}
Run Code Online (Sandbox Code Playgroud)

我能找到的所有答案都在 local ( reports) 字段上使用 $unwind ,但在这种情况下, local 字段不是数组。外部字段是数组。

怎样才能放松异域呢?有一个更好的方法吗?

我在网上看到有人建议制作另一个favorites包含以下内容的集合:

{ _id: 1, userId: 1, reportId: 1 }
{ _id: 2, userId: 1, reportId: 3 }
{ _id: 3, userId: 2, reportId: 2 }
{ _id: 4, userId: 2, reportId: 3 }
Run Code Online (Sandbox Code Playgroud)

这种方法看起来应该是不必要的。加入外部数组中的 ID 应该很简单,对吧?

mic*_*ckl 6

您可以将$lookup 与自定义管道一起使用它会给您01结果,然后使用$size将数组转换为单个布尔值:

db.reports.aggregate([
    {
        $lookup: {
            from: "users",
            let: { report_id: "$_id" },
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $and: [
                                { $eq: [ "$name", "Mike" ] },
                                { $in: [ "$$report_id", "$favorites" ] }
                            ]
                        }
                    }
                }
            ],
            as: "users"
        }
    },
    {
        $project: {
            _id: 1,
            name: 1,
            favorite: { $eq: [ { $size: "$users" }, 1 ] }
        }
    }
])
Run Code Online (Sandbox Code Playgroud)

另外,如果你需要使用MongoDB的版本比3.6更低,你可以使用常规的$lookup,然后使用$过滤器从哪里得到只有这些用户nameMike

db.reports.aggregate([
    {
        $lookup: {
            from: "users",
            localField: "_id",
            foreignField: "favorites",
            as: "users"
        }
    },
    {
        $project: {
            _id: 1,
            name: 1,
            favorite: { $eq: [ { $size: { $filter: { input: "$users", as: "u", cond: { $eq: [ "$$u.name", "Mike" ] } } } }, 1 ] }
        }
    }
])
Run Code Online (Sandbox Code Playgroud)