如何在Mongo和Mongo聚合中的文档中找到匹配?

时间:2014-10-30 14:59:57

标签: mongodb mongodb-query aggregation-framework

我在mongo集合中有以下json结构 -

 {
    "students":[
        {
        "name":"ABC",
        "fee":1233
        },
        {
        "name":"PQR",
        "fee":345
        }
    ],
    "studentDept":[
        {
        "name":"ABC",
        "dept":"A"
        },
        {
        "name":"XYZ",
        "dept":"X"
        }
    ]
},
{
    "students":[
        {
        "name":"XYZ",
        "fee":133
        },
        {
        "name":"LMN",
        "fee":56
        }
    ],
    "studentDept":[
        {
        "name":"XYZ",
        "dept":"X"
        },
        {
        "name":"LMN",
        "dept":"Y"
        },
        {
        "name":"ABC",
        "dept":"P"
        }
    ]
}

现在我想计算以下输出。 如果students.name = studentDept.name 所以我的结果应该如下

{
"name":"ABC",
"fee":1233,
"dept":"A",
},
{
"name":"XYZ",
"fee":133,
"dept":"X"
}
{
"name":"LMN",
"fee":56,
"dept":"Y"
}

我是否需要使用mongo聚合,或者是否可以在不使用聚合的情况下获得高于给定的输出???

1 个答案:

答案 0 :(得分:0)

你在这里真正要问的是如何使MongoDB返回的东西实际上与你在集合中存储它的形式完全不同。标准查询操作允许"projection"的“限制”形式,但即使在该链接中共享的页面上的标题表明,这实际上只是“限制”字段在结果中显示基于什么是已存在于您的文档中。

因此,任何形式的“更改”都需要某种形式的聚合,聚合和mapReduce操作都允许将文档结果“重新塑造”为与输入不同的形式。也许人们特别想念聚合框架的主要问题是,它不仅仅是所有关于“聚合”,实际上“重塑”概念是其实施的核心。 / p>

所以为了得到你想要的结果,你可以采取这样的方法,这应该适用于大多数情况:

db.collection.aggregate([
    { "$unwind": "$students" },
    { "$unwind": "$studentDept" },
    { "$group": {
        "_id": "$students.name",
        "tfee": { "$first": "$students.fee" },
        "tdept": {
            "$min": {
                "$cond": [
                    { "$eq": [ 
                        "$students.name", 
                        "$studentDept.name"
                    ]},
                    "$studentDept.dept",
                    false
                ]
            }
        }
    }},
    { "$match": { "tdept": { "$ne": false  } } },
    { "$sort": { "_id": 1 } },
    { "$project": {
        "_id": 0,
        "name": "$_id",
        "fee": "$tfee",
        "dept": "$tdept"
    }}
])

或者只是“过滤掉”两个“名称”字段不匹配的情况,然后只是将内容与您想要的字段一起投影,如果文档之间的内容交叉并不重要:

db.collection.aggregate([
    { "$unwind": "$students" },
    { "$unwind": "$studentDept" },
    { "$project": {
        "_id": 0,
        "name": "$students.name",
        "fee": "$students.fee",
        "dept": "$studentDept.dept",
        "same": { "$eq": [ "$students.name", "$studentDept.name" ] }
    }},
    { "$match": { "same": true } },
    { "$project": {
        "name": 1,
        "fee": 1,
        "dept": 1
    }}
])

从MongoDB 2.6及更高版本开始,您甚至可以对两个数组之间的文档执行“内联”操作。您仍然希望在最终输出中重塑该数组内容,但可能会更快一点:

db.collection.aggregate([

  // Compares entries in each array within the document
  { "$project": {
    "students": {
      "$map": {
        "input": "$students",
        "as": "stu",
        "in": {
          "$setDifference": [
            { "$map": {
              "input": "$studentDept",
              "as": "dept",
              "in": {
                "$cond": [
                  { "$eq": [ "$$stu.name", "$$dept.name" ] },
                  {
                    "name": "$$stu.name",
                    "fee": "$$stu.fee",
                    "dept": "$$dept.dept"
                  },
                  false
                ]
              }
            }},
            [false]
          ]
        }
      }
    }
  }},

  // Students is now an array of arrays. So unwind it twice
  { "$unwind": "$students" },
  { "$unwind": "$students" },

  // Rename the fields and exclude
  { "$project": {
    "_id": 0,
    "name": "$students.name",
    "fee":  "$students.fee",
    "dept": "$students.dept"
  }},
])

因此,您希望基本上“改变”输出结构,然后您需要使用其中一个聚合工具来完成。你可以,即使你没有真正聚合任何东西。