【问题标题】:Mongo db not in query by having two subset of documents from same collectionMongodb 不在查询中,因为有来自同一集合的两个文档子集
【发布时间】:2019-12-30 05:43:32
【问题描述】:

我是 mongodb 的新手。假设如下。一个集合 x、y 和 z 中有 3 种类型的文档。

docs = [{
  "item_id": 1
  "type": "x"
},
{
  "item_id": 2
  "type": "x"
},{
  "item_id": 3
  "type": "y",
  "relavent_item_ids": [1, 2]
},
{
  "item_id": 3
  "type": "y",
  "relavent_item_ids": [1, 2, 3]
},{
  "item_id": 4
  "type": "z",     
}]

我想得到以下。

  • 忽略类型为z的文档
  • 获取x 类型的所有文档,其中item_id 不在relavent_item_ids 类型的y 文档中。
  • 结果应该有item_id 字段。

我尝试做match $in 但这会返回所有记录,我无法弄清楚如何处理y 类型的文档子集。

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    您可以使用以下查询

    const item_ids = (await db.collection.find({ "type": "y" })).map(({ relavent_item_ids }) => relavent_item_ids)
    
    const result = db.collection.find({
      "item_id": { "$exists": true },
      "type": { "$ne": "z", "$eq": "x" },
      "relavent_item_ids": { "$nin": item_ids }
    })
    
    console.log({ result })
    

    忽略类型为 z 的文档 --> 使用$ne 不等于查询运算符过滤掉z 类型。

    获取所有类型 x 的文档,其中 item_id 不在 relvent_item_ids 类型 y 的文档中 --> 使用$expr 匹配相同的文档字段。

    结果应该有 item_id 字段 --> 使用$exists 查询运算符。

    【讨论】:

      【解决方案2】:

      解决办法:

      db.test.aggregate( [
        { 
            $facet: {
                firstQuery: [
                    { 
                        $match: { type: { $eq: "x", $ne: "z" } } 
                    },
                    { 
                        $project: { 
                            item_id : 1, _id: 0 
                        } 
                    }
                ],
                secondQuery: [
                    { 
                        $match: { type: "y" } 
                    },
                    { 
                        $group: { 
                            _id: null, 
                            relavent: { $push: "$relavent_item_ids" } 
                        } 
                    },
                    { 
                        $project: { 
                            relavent: { 
                                $reduce: { 
                                     input: "$relavent",
                                     initialValue:  [ ],
                                     in: { $setUnion: [ "$$value", "$$this" ] }
                                }
                            }
                        }
                    }
                ]
            } 
        },
        { 
            $addFields: { secondQuery: { $arrayElemAt: [ "$secondQuery", 0 ] } }
        },
        { 
            $project: { 
                result: {
                    $filter: { 
                         input: "$firstQuery" ,
                         as: "e",
                         cond: { $not: [ { $in: [ "$$e.item_id", "$secondQuery.relavent" ] } ] }
                    }
                }
            } 
        },
      ] )
      

      使用问题帖子中的输入文档并将以下文档添加到集合中:

      {
        "item_id": 11,
        "type": "x",     
      }
      

      :只有该文档的item_id(值11)会显示在输出中。

      聚合使用$facet 一次性进行两个单独的查询。第一个查询将所有“x”类型(并忽略“z”类型)作为一个数组。第二个查询获得一个具有唯一值的relavent_item_ids 数组(来自“y”类型的文档)。最后,$project 阶段过滤第一个查询结果数组,条件为:

      获取所有 x 类型的文档,其中 item_id 不在 类型 y 文档的 relvent_item_ids

      【讨论】:

      • 谢谢@parasd_,效果很好。方面很容易理解。我知道您正在运行两个查询,然后对它们进行操作。使用 addFields 您正在向 firstQuery 的所有文档添加一个字段,这些文档是 relventIds 列表是否正确?
      • 技术上 $ne: "z" 不是必需的。我查过了。
      • 使用 addFields 是在 firstQuery 的所有文档中添加一个字段,这些文档是 relativeIds 列表是否正确? 是的,然后用于比较。每个方面的结果是一个数组。我们不想要一个数组数组(对于 relvent_item_ids);所以我只是从 secondQuery. 中获取数组元素作为文档
      【解决方案3】:

      我不确定它是否是一个优雅的解决方案。

      db.getCollection('test').aggregate([
          {   
              "$unwind": {
                  "path": "$relavent_item_ids",
                  "preserveNullAndEmptyArrays": true
              } 
          },
          {   
              "$group": {
                  "_id":null, 
                  "relavent_item_ids": {"$addToSet":"$relavent_item_ids"},
                  "other_ids": {
                      "$addToSet":{
                          "$cond":[
                              {"$eq":["$type", "x"]},
                              "$item_id",
                              null
                          ]
                      }
                  }
              } 
          },
          {
              "$project":{ 
                      "includeIds": {"$setDifference":["$other_ids", "$relavent_item_ids"]}
              }
          },
          {
              "$unwind": "$includeIds"
          },
          {
              "$match": {"includeIds":{"$ne":null}}
          },
          {
              "$lookup":{
                      "from": "test",
                      "let": { "includeIds": "$includeIds"},
                      "pipeline": [
                            { "$match":
                               { "$expr":
                                  { "$and":
                                     [
                                       { "$eq": [ "$item_id",  "$$includeIds" ] },
                                       { "$eq": [ "$type", "x" ] }
                                     ]
                                  }
                               }
                            }
                      ],
                      "as": "result"
              }
          },
          {
              "$unwind": "$result"
          },
      ])
      

      【讨论】:

        猜你喜欢
        • 2016-12-13
        • 2017-10-17
        • 2021-09-23
        • 2015-06-12
        • 2020-12-12
        • 2018-06-27
        • 2020-05-31
        • 2014-03-15
        • 1970-01-01
        相关资源
        最近更新 更多