如何使用MongoDB find()对数字字符串执行范围查询?

时间:2016-03-14 10:34:49

标签: python mongodb

如何在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)

3 个答案:

答案 0 :(得分:2)

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

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

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之类的运算符查询数据,对其进行排序,并轻松利用索引。

答案 1 :(得分:1)

来自Mongo docs

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

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

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

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

答案 2 :(得分:0)

你可以试试这个synthax(JavaScript的自动转换):

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

source