如何查询对象中的嵌入值?

时间:2015-10-13 01:30:10

标签: mongodb mongodb-query aggregation-framework

如何编写一个查询,选择集合中values中至少有一个键具有正值的所有对象。

例如,它选择了这个:

{
  "_id" : "kDi4C9sZpq782kKJf",
  "values": {
    "a": -1,
    "b": -1,
    "c": 1234
  }
}

和这个

{
  "_id" : "kDi4C9sZpq782kKJf",
  "values": {
    "345jscf": -1,
    "6234gdr": 2341,
    "485hfls": -1
  }
}

但不是

{
  "_id" : "kDi4C9sZpq782kKJf",
  "values": {
    "a134dsd": -1,
    "bdgssvs": -1,
    "c345scv": -1
  }
}

{
  "_id" : "kDi4C9sZpq782kKJf",
  "values": {
  }
}

理想情况下,我想要一些东西 db.coll.find("values.*": {$gt: 0})

其中*匹配任何键。

修改 我已经编辑了这些值,以便更好地描述问题。

2 个答案:

答案 0 :(得分:1)

您可以尝试这样

db.collection.find({$and:[{"values":{$ne:{}}},{$or:[{"values.a":{$gt:0}},{"values.b":{$gt:0}},{"values.c":{$gt:0}}]}]}).pretty()

在您的文档中,值不是数组,因此您必须检查值文档的单个元素。

希望它会有所帮助

答案 1 :(得分:1)

您可以使用.aggregate()方法执行此操作:

db.collection.aggregate([
    { "$group": { 
        "_id": "$_id", 
        "valA": { "$push": "$values.a" }, 
        "valB": { "$push": "$values.b" }, 
        "valC": { "$push": "$values.c" }, 
        "values": { "$first": "$values" }
    }}, 
    { "$project": { 
        "values": 1, 
        "allvalues": { "$setUnion": [ "$valA", "$valB", "$valC" ] }
    }}, 
    { "$redact": { "$cond": [
        { "$anyElementTrue": [
            { "$map": {
                "input": "$allvalues", 
                "as": "av", 
                "in": { "$cond": [ 
                    { "$gt": [ "$$av", 0 ]}, 
                    true, 
                    false 
                ]}
            }}
        ]}, 
        "$$KEEP", 
        "$$PRUNE"
    ]}}
])

返回:

{
        "_id" : "kDi4C9sZpq782kKJf",
        "values" : {
                "a" : -1,
                "b" : -1,
                "c" : 1234
        },
        "allvalues" : [
                1234,
                -1
        ]
}

此查询仍然可以简化$setUnion运算符与$redact

的使用
db.collection.aggregate([
    { "$group": { 
        "_id": "$_id", 
        "valA": { "$push": "$values.a" }, 
        "valB": { "$push": "$values.b" }, 
        "valC": { "$push": "$values.c" }, 
        "values": { "$first": "$values" }
    }}, 
    { "$redact": { "$cond": [
        { "$anyElementTrue": [
            { "$map": {
                "input": { "$setUnion": [ "$valA", "$valB", "$valC" ] },
                "as": "av", 
                "in": { "$cond": [ 
                    { "$gt": [ "$$av", 0 ]}, 
                    true, 
                    false 
                ]}
            }}
        ]}, 
        "$$KEEP", 
        "$$PRUNE"
    ]}}
])

如果values键没有修复,最好的办法是使用“批量”操作更改文档结构,以获得最大效率。

var bulkOp = db.collection.initializeUnorderedBulkOp();
var count  = 0;
db.collection.find().forEach(function(doc) { 
    var values = doc.values; 
    var anotherValues = []; 
    for(var key in values) {       
        if(Object.prototype.hasOwnProperty.call(values, key)) {
            anotherValues.push({"name": key, "value": values[key]});     
        } 
    }
    bulkOp.find({ "_id": doc._id }).updateOne({ 
        "$set": { "values": anotherValues } 
    }); 
    count++; 
    if(count % 125 === 0) {     
        bulkOp.execute();     
        bulkOp = db.collection.initializeUnorderedBulkOp(); 
    } 
})

if(count > 0) { bulkOp.execute(); }

现在您的文档如下所示:

{
        "_id" : "kDi5C9sZpq782kKJf",
        "values" : [
                {
                        "name" : "a",
                        "value" : -1
                },
                {
                        "name" : "b",
                        "value" : -1
                },
                {
                        "name" : "c",
                        "value" : 1234
                }
        ]
}
{
        "_id" : "kDi4C9sZpq782kKJf",
        "values" : [
                {
                        "name" : "345jscf",
                        "value" : -1
                },
                {
                        "name" : "6234gdr",
                        "value" : 2341
                },
                {
                        "name" : "485hfls",
                        "value" : -1
                }
        ]
}

然后,您可以使用.aggregate()方法。

db.collection.aggregate([
    { "$redact": { 
         "$cond": [
             { "$anyElementTrue": [
                 { "$map": { 
                      "input": "$values", 
                      "as": "av", 
                      "in": { "$cond": [ 
                          { "$gt": ["$$av.value", 0] }, 
                          true, 
                          false
                      ]}
                 }}
             ]}, 
             "$$KEEP", 
             "$$PRUNE"
         ]
    }}
])