【问题标题】:How to use MongoDB find() to perform range queries on numeric strings?如何使用 MongoDB find() 对数字字符串执行范围查询?
【发布时间】:2016-03-14 10:34:48
【问题描述】:

我如何在 MongoDB 中创建 find(),使用 find 为 >= 某个值,但该值是数字字符串?

如果我运行以下行(在 MongoDB 数据库中搜索高于 1 的模式):

cursor = db.foo.find({"mode": {"$gt": 1}})

这只有在 MongoDB 中的数据采用以下格式时才有效:

data = {"mode":3}

但我需要将find() 与这些数据一起使用:

data = {"mode":'3'} # as string

我该怎么做?

这是我的例子:

from pymongo import MongoClient

client = MongoClient()
db = client.test

db.foo.drop()

data = {"mode":3} # Works because this is a numeric
data = {"mode":'3'} # Won't work!!!!!!!!!! But my database contains only numeric strings...how can use like this?

db.foo.insert_one(data)

print(db.foo.count())

cursor = db.foo.find({"mode": {"$gt": 1}})

for document in cursor:
    print(document)

【问题讨论】:

  • 数字字符串背后的原因是什么?您不能将其存储为数字并在应用程序级别转换为字符串吗?
  • 可惜数据库已经是这个样子了……改不了了。
  • 根据您的收藏有多大,我建议您更新您的文档并使其具有适当的类型。

标签: python mongodb


【解决方案1】:

如果您将数字数据作为字符串存储在数据库中,为了使用范围运算符(例如 $gt$lt)查询您的数据,您将不得不使用以下两种方法之一。

首先,您可以使用 JavaScript 的自动转换来运行您的范围查询。这工作如下所示,但它非常有限,因为您将 能够使用任何索引,如 cmets 对先前答案的解释。因此,对于大数据集,这将非常缓慢。

db.foo.find("this.mode > 1");

第二种方法涉及正则表达式。您必须弄清楚要使用什么正则表达式,但是一旦有了,您就可以使用下面的语法来运行您的查询,或者使用突出显示的$regex 运算符here

db.foo.find({ mode: /pattern/<options> });

除了必须弄清楚一些复杂的正则表达式之外,这种方法还可能存在性能问题,正如here 所解释的那样(请参阅下面的摘录)。您很可能还会遇到查询未利用索引的问题。

如果字段存在索引,则 MongoDB 将正则表达式与索引中的值进行匹配,这可能比集合扫描更快。如果正则表达式是“前缀表达式”,则可以进行进一步优化,这意味着所有潜在匹配都以相同的字符串开头。这允许 MongoDB 从该前缀构造一个“范围”,并且只匹配索引中落在该范围内的那些值。

因此,如果您要经常运行这些查询,我建议您采用第三种方法,即更改架构并将数据存储为数字。您可以通过一个简单的迁移脚本来实现这一点,例如以下 JavaScript 中的脚本,您可以在 shell 中运行该脚本。

var cursor = db.foo.find();
while (cursor.hasNext()) {
  var doc = cursor.next();
  var _id = doc._id;
  if (doc.mode) {
    var modeString = doc.mode;
    var modeInt = parseInt(modeString);
    db.foo.update({ _id: _id }, { $set: { mode: modeInt } });
  }
}

完成此操作后,您将能够使用 $gt$lt 等运算符查询数据,轻松对其进行排序,并利用索引。

【讨论】:

  • 当使用上面的代码时(案例3)它说:hasNext 不是一个函数。 (如何解决这个问题)
  • 你是在 shell 中运行它吗?确保您使用的是find 方法而不是findOne 方法。
【解决方案2】:

来自Mongo docs

$type 选择字段值是指定 BSON 类型实例的文档。在处理数据类型不可预测的高度非结构化数据时,按数据类型查询非常有用。 { 字段:{ $type:BSON 类型号 |字符串别名 } }

$type 返回字段的 BSON 类型与传递给 $type 的 BSON 类型匹配的文档。

我猜你必须在你的情况下明确地传递 $type 这可能是:

data = {{"mode":{$type:"string"}}:'3'}

【讨论】:

  • 谢谢。我已经尝试过: cursor = db.foo.find( {"mode": {"$type":"string" | {"$gt": 1}}} ) 但它也不起作用。我在这里做错了什么?
  • 我不确定这个答案应该做什么, $type 将返回类型为字符串的所有文档,而不是与任何内容相比的文档。它不是演员表运算符。
【解决方案3】:

你可以试试这个合成器(JavaScript 的自动转换):

db.test.find("this.mode > 1")

source

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-10
    • 1970-01-01
    • 2021-03-14
    • 1970-01-01
    • 1970-01-01
    • 2021-02-26
    相关资源
    最近更新 更多