fna*_*ira 5 php mongodb mongodb-query aggregation-framework
我想找到数组中最后一个元素等于某个值的文档.可以通过特定的数组位置访问数组元素:
// i.e. comments[0].by == "Abe"
db.example.find( { "comments.0.by" : "Abe" } )
Run Code Online (Sandbox Code Playgroud)
但我如何使用最后一项作为标准进行搜索?即
db.example.find( { "comments.last.by" : "Abe" } )
Run Code Online (Sandbox Code Playgroud)
顺便说一下,我正在使用PHP
我知道这个问题很老,但我在回答类似的新问题之后在谷歌上发现了这个问题.所以我认为这应该得到同样的待遇.
db.example.aggregate([
// Use an index, which $where cannot to narrow down
{$match: { "comments.by": "Abe" }},
// De-normalize the Array
{$unwind: "$comments"},
// The order of the array is maintained, so just look for the $last by _id
{$group: { _id: "$_id", comments: {$last: "$comment"} }},
// Match only where that $last comment by `by.Abe`
{$match: { "comments.by": "Abe" }},
// Retain the original _id order
{$sort: { _id: 1 }}
])
Run Code Online (Sandbox Code Playgroud)
这应该到处跑环$哪里,因为我们能够缩小,这些文件已经摆在首位的注释是"安倍".正如所警告的那样,$ where将测试集合中的每个文档,并且永远不会使用索引,即使有人使用索引.
当然,您也可以使用此处描述的技术维护原始文档,因此一切都可以像a一样工作find().
对于发现这一点的人来说,只是值得深思
现代版本添加了$redact管道表达式以及$arrayElemAt(后者截至3.2,因此这将是最小版本),它们组合在一起可以允许逻辑表达式在不处理$unwind阶段的情况下检查数组的最后一个元素:
db.example.aggregate([
{ "$match": { "comments.by": "Abe" }},
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Run Code Online (Sandbox Code Playgroud)
这里的逻辑是通过比较来完成的,其中$arrayElemAt获取数组的最后一个索引,该索引-1被转换为"by"属性via 中的值的数组$map.这允许将单个值与所需参数进行比较"Abe".
甚至更$expr适合MongoDB 3.6及更高版本使用它:
db.example.find({
"comments.by": "Abe",
"$expr": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
}
})
Run Code Online (Sandbox Code Playgroud)
这是迄今为止匹配数组中最后一个元素的最高性能解决方案,实际上预计会取代$where大多数情况下的使用,特别是在这里.
使用此架构设计无法一次完成此操作.您可以存储长度并执行两个查询,或者将最后一个注释另外存储在另一个字段中:
{
'_id': 'foo';
'comments' [
{ 'value': 'comment #1', 'by': 'Ford' },
{ 'value': 'comment #2', 'by': 'Arthur' },
{ 'value': 'comment #3', 'by': 'Zaphod' }
],
'last_comment': {
'value': 'comment #3', 'by': 'Zaphod'
}
}
Run Code Online (Sandbox Code Playgroud)
当然,你会复制一些数据,但ATLEAST你可以设置此数据$set与一起$push的comment.
$comment = array(
'value' => 'comment #3',
'by' => 'Zaphod',
);
$collection->update(
array( '_id' => 'foo' ),
array(
'$set' => array( 'last_comment' => $comment ),
'$push' => array( 'comments' => $comment )
)
);
Run Code Online (Sandbox Code Playgroud)
找到最后一个很容易!
您可以使用$where运算符执行此操作:
db.example.find({ $where:
'this.comments.length && this.comments[this.comments.length-1].by === "Abe"'
})
Run Code Online (Sandbox Code Playgroud)
通常$where适用于应用的缓慢性能警告。但是,您可以通过"comments.by": "Abe"在查询中包含以下内容来帮助解决此问题:
db.example.find({
"comments.by": "Abe",
$where: 'this.comments.length && this.comments[this.comments.length-1].by === "Abe"'
})
Run Code Online (Sandbox Code Playgroud)
这样,$where唯一需要针对包含 Abe 评论的文档进行评估,并且新术语将能够使用 上的索引"comments.by"。
我只是在做:
db.products.find({'statusHistory.status':'AVAILABLE'},{'statusHistory': {$slice: -1}})
Run Code Online (Sandbox Code Playgroud)
这让我知道数组中的products最后一项包含属性。statusHistorystatus='AVAILABLE'
| 归档时间: |
|
| 查看次数: |
5493 次 |
| 最近记录: |