首页 > 解决方案 > MongoDB:查询其字段之一等于其子文档字段之一的文档?

问题描述

给定以下具有相关书籍列表的书籍数据集:

{ "_id" : 1, "related_books" : [ { book_id: 1 }, { book_id: 2 }, { book_id: 3 } ] } <-- this one
{ "_id" : 2, "related_books" : [ { book_id: 1 } }
{ "_id" : 3, "related_books" : [ { book_id: 3 }, { book_id: 2 } ] } <-- and this one
{ "_id" : 4, "related_books" : [ { book_id: 1 }, { book_id: 2 } ] }

我试图在_id ===related_book.book_id时获取书籍列表,所以在这种情况下:
书1:它包含book_id = 1的related_book
书3:它包含book_id = 3的related_book

我一直在尝试使用聚合过滤器找到自己的方式,但无法通过检查子文档字段使其工作:

db.books.aggregate([{  
    "$project": {
      "selected_books": {
        "$filter": {
          "input": "$books", 
          "as":"book", 
          "cond": { "$in": ["$_id", "$$book.related_books.book_id" ]
    }}}}}])

标签: databasemongodb

解决方案


这是我对这个问题的解决方案:

db.getCollection("books").aggregate([{
    $addFields: {
        hasBookWithSameId: {
            $reduce: {
                input: "$related_books",
                initialValue: false,
                in: {$or: ["$$value", {$eq: ["$_id", "$$this.book_id"]}]}
            }
        }
    }
},
{
    $match: {
        hasBookWithSameId: true
    }
}])

在第一步中,我创建了一个表示布尔值的字段 hasBookWithSameId:如果存在具有相同 id 的相关书籍,则为 true,否则为 false。这是使用reduce操作符实现的,它是处理嵌入式数组的强大工具,它通过遍历数组来验证它是否有任何与父ID 相同的相关书籍。

最后,我只匹配所有将此属性设置为 true 的文档。

更新: 这个问题有一个更优雅的解决方案,只需一个聚合步骤,使用 $map 和 $anyElementTrue

db.collection.aggregate({
    $match: {
        $expr: {
            $anyElementTrue: {
                $map: {
                    input: "$related_books",
                    in: {
                        $eq: ["$$this.book_id", "$_id"]
                    }
                }
            }
        }
    }
})

推荐阅读