获取日期范围内的数组元素

时间:2014-06-06 12:45:31

标签: mongodb mongodb-query aggregation-framework

这是我的MongoDB集合中的示例文档:

 var user: [{
            "_id" : ObjectId("5391b11a3c0a9ac01300006d"),
            "injurydata" : {                
                "injuryinformation" : [ 
                    {
                        "status" : "current",
                        "updateddate" : ISODate("2014-06-06T12:16:20.306Z"),
                        "updatedby" : "",
                        "dateofinjury" : ISODate("2014-06-27T18:30:00.000Z"),                          
                        "_id" : ObjectId("5391b11a3c0a9ac01300006f")
                    }                   
                ]
            }
         },
         {
            "_id" : ObjectId("5391b11a3c0a9ac01300006d"),
            "injurydata" : {                
                "injuryinformation" : [ 
                    {
                        "status" : "current",
                        "updateddate" : ISODate("2014-06-06T12:16:20.306Z"),                           
                        "dateofinjury" : ISODate("2014-06-28T18:30:00.000Z"),                            
                        "_id" : ObjectId("5391b11a3c0a9ac01300006f")
                    }                   
                ]
            }
         },
         {
            "_id" : ObjectId("5391b11a3c0a9ac01300006d"),
            "injurydata" : {                
                "injuryinformation" : [ 
                    {
                        "status" : "current",                            
                        "dateofinjury" : ISODate("2014-08-10T18:30:00.000Z"),                            
                        "_id" : ObjectId("5391b11a3c0a9ac01300006f")
                    }                   
                ]
            }
         }]

从这个文档中,我只想要injuryinformation在2014-06-28和2014-06-30之间的dateofinJURY数组元素,所以我只会得到前两个元素。

我尝试了这个查询,但我仍然得到整个数组

db.user.find(
{
    $and: 
    [
        {"injury.injurydata.injuryinformation.dateofinjury": 
        {"$gte": ISODate("2014-05-21T08:00:00Z") , "$lt": ISODate("2014-06- 03T08:00:00Z")}},       
        {"_id":ObjectId("538d9a1dd173e5202a00005d")}
    ],

})

1 个答案:

答案 0 :(得分:2)

_id匹配在你的语句中是相当明确的,这样不仅会否定对数组条目的“范围”匹配的需要,而且它也会否定$and的任何使用,这实际上是隐含的在MongoDB查询中。 $and条件基本上是“默认”,除非您实际上要求同一字段上的多个条件,否则不需要.aggregate()条件。但在这里你不是。

匹配多个数组元素,您需要使用$map作为.find()可用的“投影”,不能向您显示来自数组的一个匹配条目:

db.collection.aggregate([

    // Match the document but not actually the array
    { "$match": {
        "injury.injurydata.injuryinformation.dateofinjury": {
            "$gte": ISODate("2014-05-21T08:00:00Z"), 
            "$lt": ISODate("2014-06-03T08:00:00Z")
        },       
        "_id": ObjectId("538d9a1dd173e5202a00005d")
    }},

    // Unwind the arrays to "de-normalize" as documents
    { "$unwind": "$injury" },
    { "$unwind": "$injury.injurydata" }, 
    { "$unwind": "$injury.injurydata.injuryinformation" },

    // Match the actual array elements
    { "$match": {
        "injury.injurydata.injuryinformation.dateofinjury": {
            "$gte": ISODate("2014-05-21T08:00:00Z"), 
            "$lt": ISODate("2014-06-03T08:00:00Z")
        }
    }},

    // Group those back to and array, maybe?
    { "$group": {
        "_id": "$_id",
        "information": {
            "$push": "$injury.injrydata.injuryinformation"
        }
    }}
])

或者在MongoDB 2.6及更高版本下使用{{3}}进行“过滤”,看起来更长但更快:

db.collection.aggregate([

    // Match the document but not actually the array
    { "$match": {
        "injury.injurydata.injuryinformation.dateofinjury": {
            "$gte": ISODate("2014-05-21T08:00:00Z"), 
            "$lt": ISODate("2014-06-03T08:00:00Z")
        },       
        "_id": ObjectId("538d9a1dd173e5202a00005d")
    }},

    // Unwind the arrays to "de-normalize" as documents
    { "$unwind": "$injury" },
    { "$unwind": "$injury.injurydata" }, 

    // Project with the "$map" filter
    { "$project": {
        "information": {
            "$setDifference": [
                "$map": {
                    "input": "$injury.injurydata.injuryinformation",
                    "as": "el",
                    "in": {
                        "$cond": [
                            {
                                "$and": [
                                    { 
                                        "$gte": [ 
                                            "$$el.dateofinjury",
                                            ISODate("2014-05-21T08:00:00Z")
                                        ]
                                    },
                                    {
                                        "$lt": [
                                            "$$el.dateofinjury",
                                            ISODate("2014-06-03T08:00:00Z")
                                        ]
                                    }
                                ]
                            }
                        ],
                        false
                    }
                },
                [false]
            ]
        }
    }}

])

$和条件中使用的另一种形式可用于 $match 操作之外的聚合框架表达式,等同于。{{ 1}}查询。

不确定“伤害”顶线来自哪里,因为它没有在您的样本中显示,但我认为您确实拥有它。