【问题标题】:MongoDB using $and with slice and a matchMongoDB 使用 $and 和切片和匹配
【发布时间】: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,这效率低下。

【问题讨论】:

  • @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 谢谢,我会看看是否可以在我的环境中使用它。

标签: mongodb-query spring-data


【解决方案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 中可能有更好的方法来做到这一点,但是我们固定在这个版本上,所以这必须是我们的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    • 2013-12-26
    • 2014-07-28
    • 1970-01-01
    • 1970-01-01
    • 2019-06-06
    • 1970-01-01
    相关资源
    最近更新 更多