Filter Array Content to a Query containing $concatArrays

孤者浪人 提交于 2019-12-12 17:28:56

问题


Given this function, I have a data set that I am querying. The data looks like this:

db.activity.insert(
    {
        "_id" : ObjectId("5908e64e3b03ca372dc945d5"),
        "startDate" : ISODate("2017-05-06T00:00:00Z"),
        "details" : [
            {
                "code" : "2",
                "_id" : ObjectId("5908ebf96ae5003a4471c9b2"),
                "walkDistance" : "03",
                "jogDistance" : "01",
                "runDistance" : "08",
                "sprintDistance" : "01"
            }
        ]
    }
)

db.activity.insert(
    {
        "_id" : ObjectId("58f79163bebac50d5b2ae760"),
        "startDate" : ISODate("2017-05-07T00:00:00Z"),
        "details" : [
            {
                "code" : "2",
                "_id" : ObjectId("58f7948fbebac50d5b2ae7f2"),
                "walkDistance" : "01",
                "jogDistance" : "02",
                "runDistance" : "09",
                "sprintDistance" : ""
            }
        ]
    }
)

Using this function, thanks to Neil Lunn, I am able to get my desired output:

db.activity.aggregate([
  { "$project": {
    "_id": 0,
    "unique": {
      "$filter": {
        "input": {
          "$setDifference": [
            { "$concatArrays": [ 
              "$details.walkDistance",
              "$details.jogDistance",
              "$details.runDistance",
              "$details.sprintDistance"
            ]},
            []
          ]
        },
        "cond": { "$ne": [ "$$this", "" ] }
      }
    }
  }},
  { "$unwind": "$unique" },
  { "$group": {
    "_id": null,
    "uniqueArray": { "$addToSet": "$unique" }  
  }}
])

However, I cannot add a match statement to the beginning.

db.activity.aggregate([
  {$match: {"startDate" : ISODate("2017-05-06T00:00:00Z"), "details.code": "2" },
  {$unwind: '$details'},
  {$match: {"startDate" : ISODate("2017-05-06T00:00:00Z"), "details.code": "2" },
  { "$project": {
    "_id": 0,
    "unique": {
      "$filter": {
        "input": {
          "$setDifference": [
            { "$concatArrays": [ 
              "$details.walkDistance",
              "$details.jogDistance",
              "$details.runDistance",
              "$details.sprintDistance"
            ]},
            []
          ]
        },
        "cond": { "$ne": [ "$$this", "" ] }
      }
    }
  }},
  { "$unwind": "$unique" },
  { "$group": {
    "_id": null,
    "uniqueArray": { "$addToSet": "$unique" }  
  }}
])

Because it gives an error message of:

> $concatArrays only supports arrays, not string

How can I modify this query so that a $match statement can be added?


回答1:


Don't $unwind the array you are feeding to $concatArrays. Instead apply $filter to only extract the matching values. And as stated, we can just use $setUnion for the 'unique concatenation' instead:

db.activity.aggregate([
  { "$match": { "startDate" : ISODate("2017-05-06T00:00:00Z"), "details.code": "2" } },
  { "$project": {
    "_id": 0,
    "unique": {
      "$let": {
        "vars": {
          "filtered": {
            "$filter": {
              "input": "$details",
              "cond": { "$eq": [ "$$this.code", "2" ] }
            }  
          }
        },
        "in": {
          "$setDifference": [
            { "$setUnion": [ 
              "$$filtered.walkDistance",
              "$$filtered.jogDistance",
              "$$filtered.runDistance",
              "$$filtered.sprintDistance"
            ]},
            [""]
          ]
        } 
      }
    }
  }},
  { "$unwind": "$unique" },
  { "$group": {
    "_id": null,
    "uniqueArray": { "$addToSet": "$unique" }  
  }}
])

Using $let makes things a bit cleaner syntax wise since you don't need to specify multiple $map and $filter statements "inline" as the source for $setUnion



来源:https://stackoverflow.com/questions/45809451/filter-array-content-to-a-query-containing-concatarrays

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!