获取mongodb数组中的匹配元素

时间:2015-06-16 12:25:50

标签: php mongodb aggregation-framework

我想使用聚合来获取此数组仅包含那些在2015-06-16之后具有开始字段的票证。有人可以帮我管道吗?

{
    "name" : "array",
    "tickets" : [ 
        {
            "id" : 1,
            "sort" : true,
            "start" : ISODate("2015-06-15T22:00:00.000Z")
        },
        {
            "id" : 2,
            "sort" : true,
            "start" : ISODate("2015-06-16T22:00:00.000Z")
        },
        {
            "id" : 3,
            "sort" : true,
            "start" : ISODate("2015-06-17T22:00:00.000Z")
        }
    ]
}

2 个答案:

答案 0 :(得分:1)

"标准投影"是真的。 MongoDB方法(例如.find())可用的操作最多只返回一个"单个匹配元素"从数组到查询"中的positional $ operator形式查询"部分或"投影中的$elemMatch"部分。

为了做这种"范围"操作,您需要aggregation framework,其中包含更多"操作"和"过滤"数组上的功能:

 collection.aggregate(
     array( 
         # First match the "document" to reduce the pipeline
         array(
             '$match' => array(
                 array( 
                    'tickets.start' => array(
                        '$gte' => new MongoDate(strtotime('2015-06-16 00:00:00'))
                    )
                )
             )
         ),

         # Then unwind the array
         array( '$unwind' => '$tickets' ),

         # Match again on the "unwound" elements to filter
         array(
             '$match' => array(
                 array( 
                    'tickets.start' => array(
                        '$gte' => new MongoDate(strtotime('2015-06-16 00:00:00'))
                    )
                )
             )
         ),

         # Group back to original structure per document
         array(
             '$group' => array( 
                  '_id' => '$_id',
                  'name' => array( '$first' => '$name' ),
                  'tickets' => array(
                      '$push' => '$tickets'
                  )
             )
         )           
     )
 ) 

或者您可以使用$redact运算符来简化MongoDB 2.6或更高版本,它基本上使用$cond运算符语法作为输入:

 collection.aggregate(
     array( 
         # First match the "document" to reduce the pipeline
         array(
             '$match' => array(
                 array( 
                    'tickets.start' => array(
                        '$gte' => new MongoDate(strtotime('2015-06-16 00:00:00'))
                    )
                )
             )
         ),

         # Redact entries from the array
         array(
             '$redact' => array(
                 'if' => array(
                     '$gte' => array(
                         array( '$ifNull' => array(
                             '$start',
                             new MongoDate(strtotime('2015-06-16 00:00:00'))
                         )),
                         new MongoDate(strtotime('2015-06-16 00:00:00:00'))
                     )
                 ),
                 'then' => '$$DESCEND',
                 'else' => '$$PRUNE'
             )
         )
     )
 ) 

所以两个示例执行"相同的事情" in"过滤"数组中的元素"不是"符合指定条件并返回"多于一个"元素,这是基本投射无法做到的事情。

答案 1 :(得分:0)

您应该使用Aggregation来获取输出。

您应该使用以下查询:

db.collection.aggregate({
    $match: {
    name: "array"
    }
}, {
    $unwind: "$tickets"
}, {
    $match: {
    "tickets.start": {
        $gt: ISODate("2015-06-16")
    }
    }
}, {
    $group: {
    "_id": "name",
    "tickets": {
        $push: "$tickets"
    }
    }
})