如何在筛选查找中投影数组中的特定字段

时间:2017-07-26 12:12:40

标签: mongodb mongodb-query aggregation-framework

我使用$ lookup组合两个集合,我可以在'加入'集合上应用过滤器并在起始集合上使用投影,但我没有设法在连接上结合过滤器和投影使用$ redact和$ project尝试几种方法的集合。我已经密切关注stackoverflow,但我找不到这个组合。 这是一个例子: 集合元:

{ "Exp": "A","test": "OK","date": "3"}
{ "Exp": "B","test": "OK","date": "5"}
{ "Exp": "C","test": "Failed","date": "9"}

集合合并(待加入):

{ "Exp": "A","M1": "2","M2": "test","T": "1"}
{ "Exp": "A","M1": "2","M2": "val", "T": "2"}
{ "Exp": "A","M1": "2", "M2": "val","T": "3"}
{ "Exp": "B","M1": "1", "M2": "test","M4": "1","T": "1"}
{ "Exp": "B","M1": "1","M2": "val","M4": "1","T": "2"}
{ "Exp": "B","M1": "1","M2": "val","M4": "1","T": "3"}
{ "Exp": "C","M1": "2","M2": "test","M3": "2","T": "1"}
{ "Exp": "C","M1": "2","M2": "val","M3": "2","T": "2"}
{ "Exp": "C","M1": "2","M2": "val","M3": "2","T": "3"}

查询是:使用'Exp'加入'meta'和'merge',只选择meta.test =“OK”和merge.M2 =“val”的那些,但只显示meta.Exp,meta .test和merge.M1,merge.M2和merge.T。

这是我走了多远:

db.meta.aggregate([
{ $match: { test: "OK" }},
{ $lookup:
  { from: "merge",
    localField: "Exp",
    foreignField: "Exp",
    as: "kin"
  }
 },
 { $project:
   { "Exp": true,
    "test": true,
    kin :
     { $filter:
      { input: "$kin",
        as: "kin",
        cond: { $eq: [ "$$kin.M2", "val" ]} 
      }
     }
    }
  }
])

但是尝试在merge.M1,merge.M2和merge.T以及过滤器上包含一个额外的投影会一直失败。结果应该是:

{  "Exp" : "B",
  "test" : "OK",
   "kin" : [ 
      {  "M1" : "1",
         "M2" : "val",
         "T" : "2"}, 
      {  "M1" : "1",
         "M2" : "val",
         "T" : "3"}]
 }
 { "Exp" : "A",
   "test" : "OK",
   "kin" : [ 
      { "M1" : "2",
        "M2" : "val",
        "T" : "2"}, 
      { "M1" : "2",
        "M2" : "val",
        "T" : "3"}
    ]
 } 

感谢您的提示! Jordi

2 个答案:

答案 0 :(得分:0)

使用$map指定要返回的数组的字段:

db.meta.aggregate([
  { "$match": { test: "OK" }},
  { "$lookup":{ 
    "from": "merge",
    "localField": "Exp",
    "foreignField": "Exp",
    "as": "kin"
  }},
  { "$project": {
    "Exp": 1,
    "test": 1,  
    "kin": {
      "$map": {
        "input": {
          "$filter": {
            "input": "$kin",
            "as": "k",
            "cond": { "$eq": [ "$$k.M2", "val" ] }
          }  
        },
        "as": "k",
        "in":  {
          "M1": "$$k.M1",
          "M2": "$$k.M2",
          "T": "$$k.T"  
        }  
      }  
    }  
  }}
])

为您返回:

/* 1 */
{
    "_id" : ObjectId("5979a8857dcd6a5f6a9b4b9a"),
    "Exp" : "A",
    "test" : "OK",
    "kin" : [ 
        {
            "M1" : "2",
            "M2" : "val",
            "T" : "2"
        }, 
        {
            "M1" : "2",
            "M2" : "val",
            "T" : "3"
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("5979a8857dcd6a5f6a9b4b9b"),
    "Exp" : "B",
    "test" : "OK",
    "kin" : [ 
        {
            "M1" : "1",
            "M2" : "val",
            "T" : "2"
        }, 
        {
            "M1" : "1",
            "M2" : "val",
            "T" : "3"
        }
    ]
}

答案 1 :(得分:0)

另一种方法,由colleaque提出使用第二个$投影。我认为这比$ map更有效,因为它不会遍历数组的每个元素。诀窍是重复第一个$投影的预测。

db.meta.aggregate([
  { $match: { test: "OK" }},
  { $lookup: { from: "merge", localField: "Exp", foreignField: "Exp", as: 
     "kin" }},
  { $project:
    { "Exp": true, "test": true, "date": true,
      kin : { $filter: { input: "$kin", as: "kin", cond: { $eq: [ 
      "$$kin.M2", 
      "val" ]}}
     }
   }
  },
  { $project: { 
    "Exp": true, "test": true, "date": true,
    "kin.M1": true, "kin.M2": true, "kin.T": true }
   }
])