【问题标题】:Mongodb: Query on the last N documents(some portion) of a collection onlyMongodb:仅查询集合的最后 N 个文档(某些部分)
【发布时间】:2021-07-24 15:24:18
【问题描述】:

在包含 100 个文档的集合中,我想运行以下查询:

collection.find({"$text" : {"$search" : "some_string"})

假设一个合适的“文本”索引已经存在,因此我的问题是:我怎样才能只对最后'n'个文档运行这个查询?

我在网上找到的所有问题都是关于如何获取最后 n 个文档。而我的问题是如何搜索仅在最后 n 个文档上?

更一般地说,我的问题是如何在某个部分运行 mongo 查询,比如 20% 的集合。

我尝试了什么

我正在使用 pymongo,所以我尝试使用 skip() 和 limit() 来获取最后 n 个文档,但我没有找到对上述函数返回的游标执行查询的方法。

@hhsarh's anwser 之后,我尝试了但无济于事

# here's what I tried after initial answers
recents = information_collection.aggregate([
                {"$match" : {"$text" : {"$search" : "healthline"}}},
                {"$sort" : {"_id" : -1}},
                {"$limit" : 1},
            ])

结果仍然来自整个集合,而不是上述代码尝试的最后一条记录/文档。

最后一个文档的任何字段都不包含“healthline”,因此查询的预期结果应该为空 []。但我得到了一份文件。

请有人告诉我这是怎么可能的

【问题讨论】:

  • 有人有更好的答案吗?

标签: mongodb mongodb-query pymongo


【解决方案1】:

您正在寻找的可以使用 MongoDB 聚合实现

注意:正如@turivishal 所指出的,如果$text 不在聚合管道的第一阶段,它将不起作用。

collection.aggregate([
  {
    "$sort": {
      "_id": -1
    }
  },
  {
    "$limit": 10  // `n` value, where n is the number of last records you want to consider
  },
  {
    "$match" : {
      // All your find query goes here
    }
  },
], {allowDiskUse=true})  // just in case if the computation exceeds 100MB

由于_id是默认索引的,所以上面的聚合查询应该会更快。但是,它的性能与n 值成正比。

注意:如果您使用的是pymongo,请将代码示例中的最后一行替换为以下行

], allowDiskUse=True)

【讨论】:

  • 查询无效,包含$text$match 阶段必须是管道中的第一个阶段。见$text restrictions
  • 是的,那是因为您必须添加要搜索的键来代替 $match。我已经更新了答案。
  • 请分享完整的键名和要搜索的值
  • 我不是OP,如果我没记错的话OP想用$text搜索(运营商),或者你可以等待他的回复。
  • 好的,我现在知道了。我的回答是错误的。感谢您指出。猜猜$text 必须在$match 阶段被放弃。有什么解决方法吗?
【解决方案2】:

$text 运算符是不可能的,因为有限制,

包含$text$match 阶段必须是管道中的第一个阶段

这意味着我们不能在$text 运算符之前限制文档,请阅读更多关于$text operator restriction 的信息。


如果您使用$regex 正则表达式运算符而不是$text 运算符进行搜索,这可能是第二个选项,

如果您需要像$text 运算符一样搜索,您可以修改您的搜索输入,如下所示:

  • 让我们假设 searchInput 是您的输入变量
  • searchFields 中的搜索字段列表
  • 按空格搜索输入字符串并循环该单词数组并将其转换为正则表达式
  • 循环搜索字段searchFields 并准备$in 条件
searchInput = "This is search"
searchFields = ["field1", "field2"]
searchRegex = []
searchPayload = []

for s in searchInput.split(): searchRegex.append(re.compile(s, re.IGNORECASE));
for f in searchFields: searchPayload.append({ f: { "$in": searchRegex } })
print(searchPayload)

现在你的输入看起来像,

[
  {'field1': {'$in': [/This/i, /is/i, /search/i]}}, 
  {'field2': {'$in': [/This/i, /is/i, /search/i]}}
]

在最后阶段使用$in 运算符在搜索查询中使用该变量searchPayload$or 运算符,

recents = information_collection.aggregate([
  # 1 = ascending, -1 descending you can use anyone as per your requirement
  { "$sort": { "_id": 1 } }, 
  # use any limit of number as per your requirement
  { "$limit": 10 }, 
  { "$match": { "$or": searchPayload } }
])

print(list(recents))

注意:$regex 正则表达式搜索会导致性能问题。

要提高搜索性能,您可以在搜索字段上创建复合索引,例如,

information_collection.createIndex({ field1: 1, field2: 1 });

【讨论】:

  • 这是最好的方法吗?
  • 在单个查询中没有其他方法可以满足您的要求,我不能说这是您项目要求的最佳方法。
  • 感谢您的努力。我决定在项目中使用中间集合。 Mongo 有朝一日可能会为此提供一项功能。
猜你喜欢
  • 2014-01-06
  • 1970-01-01
  • 2017-08-03
  • 1970-01-01
  • 2020-06-14
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 2016-02-22
相关资源
最近更新 更多