【问题标题】:Unable to filter by date the array field of a Collection in MongoDB无法按日期过滤 MongoDB 中集合的数组字段
【发布时间】:2014-08-14 08:26:51
【问题描述】:

我正在努力使用 MongoDb 以获得理想的结果。

我的收藏看起来像:

{
 _id: ...
 place: 1
 city: 6
 user: 306
 createDate: 2014-08-10 12:20:21,
 lastUpdate: 2014-08-14 10:11:01,
 data: [
   {
     customId4: 4,
     entryDate: 2014-07-12 12:01:11,
     exitDate: 2014-07-12 13:12:12
   },
   {
     customId4: 4,
     entryDate: 2014-07-14 00:00:01,
   },
   {
     customId4: 5,
     entryDate: 2014-07-15 11:01:11,
     exitDate: 2014-07-15 11:05:15
   },
   {
     customId4: 5,
     entryDate: 2014-07-22 21:01:11,
     exitDate: 2014-07-22 21:23:22
   },
   {
     customId4: 4,
     entryDate: 2014-07-23 14:00:11,
   },
   {
     customId4: 4,
     entryDate: 2014-07-29 22:00:11,
     exitDate: 2014-07-29 23:00:12
   },
   {
     customId4: 5,
     entryDate: 2014-08-12 12:01:11,
     exitDate: 2014-08-12 13:12:12
   },
 ]
}

所以我想要实现的是满足一定区间要求并且同时设置了entryDate和exitDate值的数组数据。

例如,如果我按间隔“2014-07-23 00:00:00 到 2014-08-31 00:00:00”过滤,我希望得到如下结果:

{
  result: [
    {
       _id: {
           place: 1,
           user: 306
       },
       city: 6,
       place: 1,
       user: 306,
       data: [
          {
            customMap: 4,
            entryDate: 2014-07-22 21:01:11,
            exitDate: 2014-07-22 21:23:22
          },
          {
            customId4: ,
            entryDate: 2014-07-29 22:00:11,
            exitDate: 2014-07-29 23:00:12
          },
       ]
    }
  ],
  ok: 1
}

我的自定义 mongodb 查询看起来像(from、to 和 placeIds 是正确配置的变量)

db.myColl.aggregate(
    { $match: { 
        'user': 1, 
        'data.entryDate': { $gte: from, $lte: to },
        'place': { $in: placeIds },
    }},
    { $unwind : "$data" },
    { $project: {
        'city': 1, 
        'place': 1,
        'user': 1,
        'lastUpdate': 1,
        'data.entryDate': 1,
        'data.exitDate': 1,
        'data.custom': 1,
        fromValid: { $gte: ["$'data.entryDate'", from]},
        toValid: { $lte: ["$'data.entryDate'", to]}}
    },
        { $group: {
        '_id': {'place': '$place', 'user': '$user'},
        'city': {'$first': '$city'},
        'place': {'$first': '$place'},
        'user': {'$first': '$user'},
        'data': { '$push': '$data'}
}}
)

但这并没有按照我想要的方式过滤,因为它输出每个满足 $match 操作数条件的文档,在 $project 操作数内我无法定义条件(我不知道这是不是这样在 mongoDB 中完成)

提前致谢!

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    您在正确的轨道上,但是聚合“管道”可能缺少的是就像“|”一样在 unix shell 中,管道运算符将管道阶段“链接”在一起,就像链接命令一样。

    所以实际上可以有第二个$match 管道阶段为您进行过滤:

    db.myColl.aggregate([
        { "$match": { 
            "user": 1, 
            "data.entryDate": { "$gte": from, "$lte": to },
            "place": { "$in": "placeIds" },
        }},
        { "$unwind": "$data" },
        { "$match": { 
            "data.entryDate": { "$gte": from, "$lte": to },
        }},
        { "$group": {
            "_id": "$_id",
            "place": { "$first": "$place" },
            "city": { "$first": "$city" },
            "user": { "$first": "$user" },
            "data": { "$push": "$data" }
        }}
    ])
    

    使用文档的实际 _id 作为分组键,假设您想要返回文档,但只是使用过滤后的数组。

    从 MongoDB 2.6 开始,只要匹配的数组元素是唯一的,您就可以使用 $map$setDifference** 运算符在 $project 中执行相同的操作:

    db.myColl.aggregate([
        { "$match": { 
            "user": 1, 
            "data.entryDate": { "$gte": from, "$lte": to },
            "place": { "$in": "placeIds" },
        }},
        { "$project": {
            "place": 1,
            "city": 1,
            "user": 1,
            "data": {
               "$setDifference": [
                   { "$map": {
                       "input": "$data",
                       "as": "el",
                       "in": {"$cond": [
                           { "$and": [
                               { "$gte": [ "$$el.entryDate", from ] },
                               { "$lte": [ "$$el.entryDate", to ] }
                           ]},
                           "$$el",
                           false
                       ]}
                   }},
                   [false]
               ]
            }
        }}
     ])
    

    通过处理每个数组元素并评估它是否满足条件来执行相同的逻辑操作。如果是,则返回元素内容,如果不是,则返回 false$setDifference 过滤掉所有 false 值,以便只保留匹配的值。

    【讨论】:

    • 非常感谢,太完美了。太棒了!
    猜你喜欢
    • 2022-10-05
    • 1970-01-01
    • 1970-01-01
    • 2021-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多