【问题标题】:Multiple $where queries in MongoDBMongoDB 中的多个 $where 查询
【发布时间】:2014-12-13 15:47:01
【问题描述】:

我尝试将以下查询放在一起,但它不起作用:

db.sss.find({
    "pos": { "$gte": 200000, "$lt": 2000000 },
    "$where": "(this.chr.letter != "X" && this.chr.no == 5) && (this.chr.letter != "X" && this.chr.no == 6) && (this.chr.letter != this.chr.letter)"
})

上面的情况我试着在下面解释一下:

  • chr.no = 5chr.no = 6
  • chr 中的两个对象/dicts 之间的chr.letter 不一样且没有X,并且
  • 文档必须在 200000 - 2000000 范围内

示例输出可能如下所示:

  • {"x_type":"7", "sub_name":"B01", "name":"A", "pos":828288, "s_type":1}
  • {"x_type":"9", "sub_name":"B01", "name":"A", "pos":871963, "s_type":3}

文档"x_type":"8" 不满足范围条件。文档 "x_type":"10" 无效,因为 chr.no = 6 具有 chr.letter = X。 并且文档"x_type":"14" 无效,因为 chr.no = 5 和 chr.no = 6 都具有相同的 chr.letter = G

该数据库包含以下文档:

{
  "_id":ObjectId("5441b57bb6d08aa98ee8d34f"),
  "name":"A",
  "pos":828288,
  "s_type":1,
  "sub_name":"B01",
  "type":"Test",
  "x_type":7,
  "chr":[
      {
        "letter":"C",
        "no":4
      },
      {
        "letter":"C",
        "no":5
      },
      {
        "letter":"T",
        "no":6
      }
  ]
}{
  "_id":ObjectId("5441b57cb6d08aa98ee8d350"),
  "name":"A",
  "pos":171878,
  "s_type":3,
  "sub_name":"B01",
  "type":"Test",
  "x_type":8,
  "chr":[
      {
        "letter":"C",
        "no":5
      },
      {
        "letter":"T",
        "no":6
      }
  ]
}{
  "_id":ObjectId("5441b57cb6d08aa98ee8d351"),
  "name":"A",
  "pos":871963,
  "s_type":3,
  "sub_name":"B01",
  "type":"Test",
  "x_type":9,
  "chr":[
      {
        "letter":"A",
        "no":5
      },
      {
        "letter":"G",
        "no":6
      }
  ]
}{
  "_id":ObjectId("5441b57cb6d08aa98ee8d352"),
  "name":"A",
  "pos":1932523,
  "s_type":1,
  "sub_name":"B01",
  "type":"Test",
  "x_type":10,
  "chr":[
      {
        "letter":"T",
        "no":4
      },
      {
        "letter":"A",
        "no":5
      },
      {
        "letter":"X",
        "no":6
      }
  ]
}{
  "_id":ObjectId("5441b57cb6d08aa98ee8d353"),
  "name":"A",
  "pos":667214,
  "s_type":1,
  "sub_name":"B01",
  "type":"Test",
  "x_type":14,
  "chr":[
      {
        "letter":"T",
        "no":4
      },
      {
        "letter":"G",
        "no":5
      },
      {
        "letter":"G",
        "no":6
      }
  ]
}

我使用以下脚本创建了上述数据库:

from pymongo import MongoClient
from collections import defaultdict


db = MongoClient().test
sDB = db.sss

r = [["Test", "A", "B01", 828288,  1,    7, 'C', 4],
    ["Test", "A", "B01", 828288,  1,    7, 'C', 5],
    ["Test", "A", "B01", 828288,  1,    7, 'T', 6],
    ["Test", "A", "B01", 171878,  3,    8, 'C', 5],
    ["Test", "A", "B01", 171878,  3,    8, 'T', 6],
    ["Test", "A", "B01", 871963,  3,    9, 'A', 5],
    ["Test", "A", "B01", 871963,  3,    9, 'G', 6],
    ["Test", "A", "B01", 1932523, 1,   10, 'T', 4],
    ["Test", "A", "B01", 1932523, 1,   10, 'A', 5],
    ["Test", "A", "B01", 1932523, 1,   10, 'X', 6],
    ["Test", "A", "B01", 667214,  1,   14, 'T', 4],
    ["Test", "A", "B01", 667214,  1,   14, 'G', 5],
    ["Test", "A", "B01", 667214,  1,   14, 'G', 6]]

for i in r:
    sDB.update({'type': i[0],
          'name': i[1],
          'sub_name': i[2],
          'pos': i[3],
          's_type': i[4],
          'x_type': i[5]},
          {"$push": {
              "chr":{
                  "letter":i[6],
                  "no": i[7]} }},
          True)

如何解决上述查询?

【问题讨论】:

  • 记住使用 $where 会效率低下

标签: javascript python mongodb pymongo


【解决方案1】:

我猜你在某种程度上混合了 JavaScript 和 MongoDB 之间的语法。
$where 由服务器端的 JavaScript 引擎执行,所以你的 $where 语句 必须符合 JavaScipt 的语法。例如,this.chr.no == 5 实际上是 this.chr[index].no == 5,正如您所期望的那样;并且一个变量不可能同时等于两个不同的值。以下代码供您参考:

var judge = function () {
    var unexpect = "X";
    var letter1 = unexpect, letter2 = unexpect;
    for (var i in this.chr) {
        var chr = this.chr[i];
        if (chr.no == 5) {
            letter1 = chr.letter;
        } else if (chr.no == 6) {
            letter2 = chr.letter;
        }
    }
    if (letter1 != letter2 && letter1 != unexpect && letter2 != unexpect) {
        return true;
    }
    return false;
};

db.sss.find({
    "pos": { "$gte": 200000, "$lt": 2000000 },
    "$and" : [{"chr.no" : 5}, {"chr.no" : 6}],    // narrow range further
    "$where": judge
}, {"x_type":1, "sub_name":1, "name":1, "pos":1, "s_type":1, _id:0});

【讨论】:

    【解决方案2】:

    我假设您的 $where 逻辑有问题。你描述的方式:

    (this.chr.letter != "X" && this.chr.no == 5) &&
    (this.chr.letter != "X" && this.chr.no == 6) &&
    (this.chr.letter != this.chr.letter)
    

    不会返回任何内容,因为 this.chr.no 不能同时是 56。很可能您希望在括号之间加上||

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-05
      • 1970-01-01
      • 2020-08-01
      • 1970-01-01
      • 2020-06-11
      • 1970-01-01
      • 1970-01-01
      • 2020-12-15
      相关资源
      最近更新 更多