MongoDB 使用 $and 和切片和匹配
Posted
技术标签:
【中文标题】MongoDB 使用 $and 和切片和匹配【英文标题】:MongoDB using $and with slice and a match 【发布时间】:2018-07-02 15:22:33 【问题描述】:我正在使用 spring 数据包中的 @Query,我想查询文档中数组的 last 元素。
例如数据结构可能是这样的:
name : 'John',
scores: [10, 12, 14, 16]
,
name : 'Mary',
scores: [78, 20, 14]
,
所以我建立了一个查询,但是它抱怨 “错误消息 'unknown operator: $slice' on server”
查询的 $slice 部分在单独运行时很好:
db.getCollection('users').find(, scores: $slice: -1 )
但是,一旦我将它与更复杂的检查结合起来,就会出现上述错误。
db.getCollection('users').find"$and":[ , "scores" : "$slice" : -1 ,"scores": "16"])
此查询将返回最后得分为 16 的用户列表,在我的示例中将返回 John,但不返回 Mary。
我已将其放入标准的 mongo 查询中(用于调试事物),但理想情况下我需要将其放入 spring-data @query 构造中 - 它们应该非常相似。
有没有办法做到这一点,而不求助于手动 java 调用?除了需要标准查询之外,我没有看到太多关于 @Query 的文档。
正如链接帖子所评论的那样,它指的是聚合,它如何与@Query一起使用,加上主要答案之一使用$where,这效率低下。
【问题讨论】:
MongoDB - Query on the last element of an array?的可能重复 @Veeram 我在那里看不到合适的答案,他们要么使用聚合 - 这在 @Query 指令中如何工作 - 我在文档中看不到任何内容,也是主要答案之一使用$where 又不适合,因为它非常慢。可能有 1000 个条目。 没有@Query 答案。我认为最好的答案是以相反的顺序存储文档,您可以在其中访问具有 .0 索引的顶部文档。像db.getCollection('users').find("scores.0": 16)
这样的东西。如果这不是一个选项,您必须使用 MongoTemplate 来访问聚合方法。
想一想你现在可以使用 3.6 中的 $expr
运算符在查找查询中使用聚合函数。所以像@Query 中的$expr:$gt:[$arrayElemAt:["scores", -1], 16]
这样的东西。您可以在 3.6 shell 中尝试db.getCollection('users').find($expr:$gt:[$arrayElemAt:["scores", -1], 16])
。我已经更新了链接的帖子以包含新的答案。在 Spring Query 指令中测试并且它有效!试试@Query("$expr:$gt:[$arrayElemAt:[\"scores\", -1], ?0]")
@Veeram 谢谢,我会看看是否可以在我的环境中使用它。
【参考方案1】:
不幸的是,解决问题的一般方法是数据,尽管@Veeram 的响应是正确的,但这意味着您没有命中索引。这是一个问题,您当然拥有非常大的数据集,并且您会看到返回时间不断减少。这是 $where,$arrayElemAt 无法帮助您解决的问题。他们必须对数据进行预处理,这意味着要进行完整的收集扫描。我们使用这些结构分析了几个查询,它们涉及“COLSCAN”。
理想的解决方案是创建一个包含最后一项的字段,例如:
name : 'John',
scores: [10, 12, 14, 16],
lastScore: 16
,
name : 'Mary',
scores: [78, 20, 14],
lastScore: 14
您可以创建一个监听器来维护它,如下所示:
@Component
public class ScoreListener extends AbstractMongoEventListener<Scores>
然后您就可以嗅探数据并进行任何更新:
@Override
public void onBeforeConvert(BeforeConvertEvent<Scores> event)
// process any score and set lastScore
别忘了更新你的索引(!):
@CompoundIndex(name = "lastScore", def = ""
+ "'lastScore': 1"
+ " ")
虽然这确实包含数据轻微重复的缺点,但在当前的 Mongo (3.4) 中,这确实是这样做的唯一方法,并且在搜索机制中包含索引。速度差异很大,从近一分钟的响应时间到几毫秒。
在 Mongo 3.6 中可能有更好的方法来做到这一点,但是我们固定在这个版本上,所以这必须是我们的解决方案。
【讨论】:
以上是关于MongoDB 使用 $and 和切片和匹配的主要内容,如果未能解决你的问题,请参考以下文章
mongodb 中 Aggregation 的管道和分片集合( Pipeline and Sharded Collections)