我想使用聚合来获取此数组仅包含那些在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")
}
]
}
答案 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"
}
}
})