使用匹配内部数组项的总计重新映射数组

时间:2017-08-08 11:41:49

标签: arrays mongodb mongodb-query aggregation-framework

我的文档集如下所示:

[
  {
    "_id": {
      "$oid": "596e004151cc92046c28dd39"
    },
    "routes": [
      {
        "legs": [
          {
            "LegId":0,
            "end_address": "B",
            "start_address": "A",
             "price":123
          },
          {
            "LegId":1,
            "end_address": "C",
            "start_address": "B",
             "price":123

          },
          {
            "LegId":2,
            "end_address": "D",
            "start_address": "C",
             "price":120
          },
          {
            "LegId":3,
            "end_address": "E",
            "start_address": "D",
              "price":125
          }
        ]
      }
    ],
    "status": "OK",
    "Date": {
      "$date": "2017-07-18T12:34:07.781Z"
    }
  },
  {
    "_id": {
      "$oid": "596e007d51cc9231a8117607"
    },
    "routes": [
      {
        "legs": [
          {
            "LegId":0,
            "end_address": "E",
            "start_address": "F",
              "price":300
          },
          {
            "LegId":1,
            "end_address": "D",
            "start_address": "E",
              "price":200
          },
          {
            "LegId":2,
            "end_address": "C",
            "start_address": "D",
              "price":200
          },
          {
            "LegId":3,
            "end_address": "B",
            "start_address": "C",
              "price":200
          }
        ]
      }
    ],
    "status": "OK",
    "Date": {
      "$date": "2017-07-18T12:35:09.121Z"
    }
  }
]

我需要在StartAddress =" A和end Address =" D"之间预测状态,日期和腿的总价。 (通过传递起始地址和结束地址找到腿ID,并在legId上使用$ gt和$ lt)

仅供参考:至于查找顶级文档,我在每个文档中使用祖先字段来过滤2所需文档。

抱歉,如果我对这种语言感到困惑。

1 个答案:

答案 0 :(得分:1)

其余部分主要是$filter$map$sum的应用:

db.collection.aggregate([
  // Still actually query for documents that meet the later filter conditions
  { "$match": {
    "routes": {
      "$elemMatch": {
        "legs": {
          "$elemMatch": {
            "start_address": { "$gte": "A" },
            "end_address": { "$lte": "D" }
          }
        }
      }
    }
  }},
  // Just return the wanted array fields and the sum of the matching inner
  { "$addFields": {
    "routes": {
      "$map": {
        "input": "$routes",
        "as": "r",
        "in": {
          "Status": "$$r.Status",
          "Date": "$$r.Date",
          "totalPrice": {
            "$sum": {
              "$map": {
                "input": {
                  "$filter": {
                    "input": "$$r.legs",
                    "as": "l",
                    "cond": {
                      "$and": [
                        { "$gte": [ "$$l.start_address", "A" ] },
                        { "$lte": [ "$$l.end_address", "D" ] }
                      ]
                    }
                  }
                },
                "as": "l",
                "in": "$$l.price"
              }
            }
          }
        }
      }
    }
  }}
])

为了解释这一点,有几个部分。首先,外部$map迭代外部"routes"数组并简单地返回所有这些条目。如果我们想要"过滤"这里的任何内容我们同样会将$filter应用于此$map"input",但除了返回"totalPrice"之外,您的问题并不表示任何其他内容。

所以其他数组属性只是在输出中命名,就像" map"在任何其他语言实现中。对于"totalPrice",您显然需要$sum,但我们需要使用$filter来匹配数组元素,然后使用$map来获取特定字段"price"实际提供$sum

此处$filter的参数在"cond"中指定,您使用"逻辑形式" $gte$lte返回一个布尔结果,与参数一样,只保留那些数组成员。 $and通过确保两个内部参数都需要返回true以便返回true来扩展该逻辑条件。