MongoDB $ elemMatch找不到合适的结果

时间:2014-10-16 06:33:36

标签: python mongodb mongodb-query pymongo

下面是一个小型的MongoDB数据库:

> db.sss.find().pretty()
{
    "_id" : ObjectId("543f53b8711761110238be74"),
    "name" : "A",
    "pos" : 828288,
    "s_type" : 1,
    "sub_name" : "B01",
    "type" : "Test",
    "x_type" : 7,
    "chr" : [
        {
            "5" : "C"
        },
        {
            "6" : "T"
        }
    ]
}
{
    "_id" : ObjectId("543f53b8711761110238be75"),
    "name" : "A",
    "pos" : 171878,
    "s_type" : 3,
    "sub_name" : "B01",
    "type" : "Test",
    "x_type" : 8,
    "chr" : [
        {
            "5" : "C"
        },
        {
            "6" : "T"
        }
    ]
}
{
    "_id" : ObjectId("543f53b8711761110238be76"),
    "name" : "A",
    "pos" : 871963,
    "s_type" : 3,
    "sub_name" : "B01",
    "type" : "Test",
    "x_type" : 9,
    "chr" : [
        {
            "5" : "A"
        },
        {
            "6" : "G"
        }
    ]
}
{
    "_id" : ObjectId("543f53b8711761110238be77"),
    "name" : "A",
    "pos" : 1932523,
    "s_type" : 1,
    "sub_name" : "B01",
    "type" : "Test",
    "x_type" : 10,
    "chr" : [
        {
            "4" : "T"
        },
        {
            "5" : "A"
        },
        {
            "6" : "X"
        }
    ]
}
{
    "_id" : ObjectId("543f53b8711761110238be78"),
    "name" : "A",
    "pos" : 667214,
    "s_type" : 1,
    "sub_name" : "B01",
    "type" : "Test",
    "x_type" : 14,
    "chr" : [
        {
            "4" : "T"
        },
        {
            "5" : "G"
        },
        {
            "6" : "G"
        }
    ]
}

以上脚本创建了上述数据库:

from pymongo import MongoClient
from collections import defaultdict


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

r = [["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":{str(i[7]): i[6]} }}, True)

我开始针对以下条件编写查询:

  • x_type:7x_type:9是正确的,因为chr.5chr.6具有不同的字符,而且它们都没有字符X.
  • x_type:8是正确的,但超出范围(200000到2000000)
  • x_type:10无效,因为chr.6包含X
  • x_type:14无效,因为chr.5chr.6具有相同的字符

但是,我没有通过以下草稿查询得到我想要的内容:

> db.snps.find({"pos": {$gte: 200000, $lt: 2000000}}, {"chr":{$elemMatch:{"6":{$ne: "X"}}}}).pretty()
{
    "_id" : ObjectId("543f53b8711761110238be74"),
    "chr" : [
        {
            "5" : "C"
        }
    ]
}
{
    "_id" : ObjectId("543f53b8711761110238be76"),
    "chr" : [
        {
            "5" : "A"
        }
    ]
}
{
    "_id" : ObjectId("543f53b8711761110238be77"),
    "chr" : [
        {
            "4" : "T"
        }
    ]
}
{
    "_id" : ObjectId("543f53b8711761110238be78"),
    "chr" : [
        {
            "4" : "T"
        }
    ]
}

我做错了什么?

1 个答案:

答案 0 :(得分:1)

您似乎在使用错误的$elemMatch形式,因为您使用的是“投影”形式,用于选择数组中第一个匹配条件你提供的。您在此处指定的唯一“查询”条件是“pos”值落在请求的范围内。

如果您想要的是两者,则条件存在于文档在该范围内具有“pos”值并且“chr.6”中没有“X”值的情况。在比较数组元素的值时,final和additional子句有点棘手。但是这可以通过$where的JavaScript评估来实现,只要只有并且总是有两个元素,这是非常简单的:

db.snps.find({
    "pos": { "$gte": 200000, "$lt": 2000000 },
    "chr.6": { "$ne": "X" },
    "$where": "this.chr[0]['5'] != this.chr[1]['6']"
})

对于其他组合或命名元素来说有点棘手,但JavaScript评估的相同原则适用于该条件。

因此,由于仅测试数组元素的一个字段,因此您不需要$elemMatch的查询形式,因此投影位于错误的位置。你想要一个“查询”条件,选择符合它们的文件。