【问题标题】:Pymongo Advanced query (embeded objects and arrays)Mongodb 高级查询(嵌入对象和数组)
【发布时间】:2016-12-29 00:22:07
【问题描述】:

我已经为此工作了大约一个星期,学到了很多关于 pymongo 的知识但仍然无法破解它。

我在 mongo 中有以下 JSON

{ 
    "_id" : ObjectId("5845e25xxxxxxxxxx"), 
    "timestamp" : ISODate("2016-08-24T14:59:04.000+0000"), 
    "new_key" : "cambiar", 
    "Records" : [
        {
            "RecordType" : "WFD", 
            "Properties" : [
                {
                    "Property" : {
                        "IsReadOnly" : "False", 
                        "ValueType" : "System", 
                        "Name" : "LastWrite"
                    }, 
                    "value" : "42"
                }, 
                {
                    "Property" : {
                        "IsReadOnly" : "True", 
                        "ValueType" : "String", 
                        "Name" : "Time_as_String"
                    }, 
                    "value" : "24-08-2016 14:59:08"
                }, 
                {
                    "Property" : {
                        "IsReadOnly" : "False", 
                        "ValueType" : "32", 
                        "Name" : "YES"
                    }, 
                    "value" : "1472065148"

下面还有更多属性。我试图只返回“值”:1472065148,仅此而已。我已经写了这个查询

x = dataset.find_one({"Records.Properties.Property.Name":'YES'},{"Records.Properties.Property.value":1})

但是因为“价值”与所有其他价值处于同一水平,所以我得到了所有价值结果,而不仅仅是我希望的结果。

有没有办法在匹配查询的object之后只打印结果object???? “名称”:“是”是我要查询的对象,“值”:“1472065148”是我要打印的对象。

------------ 附加部分---------------

上面是一个文档,其中包含我想要检索的 'name' : 'Yes' 值。但是,每个文档内部都有相同的“名称:是”。我想做的是首先根据不同的“名称”选择文档:“xxxx”的值。例如上面 - 查找 'name' : 'lastwrite' 在检索 'name' : 'YES' 值之前检查其值是否为 42(因此选择此文档而不是其他文档)(如您给我的答案) .

(如果这算作一个新问题,请告诉我,我将删除它并发布一个新问题)

【问题讨论】:

    标签: mongodb mongodb-query pymongo


    【解决方案1】:

    现有结构的唯一选择是使用聚合。

    db.dataset.aggregate([{
        $unwind: "$Records"
    }, {
        $unwind: "$Records.Properties"
    }, {
        $match: {
            "Records.Properties.Property.Name": 'YES'
        }
    }, {
        $project: {
            "_id": 0,
            "value": "$Records.Properties.value"
        }
    }]).pretty()
    

    示例响应

    { "value" : "1472065148" }
    

    假设您能够按如下方式更新您的结构(为简洁起见,删除了一些字段)。这里的变化是 Records 不再是一个数组,而是一个嵌入的文档。

    db.dataset.insertMany([{
      "timestamp": ISODate("2016-08-24T14:59:04.000+0000"),
      "Records": {
          "RecordType": "WFD",
          "Properties": [{
              "Property": {
                  "Name": "LastWrite"
              },
              "value": "42"
          }, {
              "Property": {
                  "Name": "YES"
              },
              "value": "1472065148"
          }]
      }
    }])
    

    查询

    db.dataset.find({"Records.Properties.Property.Name":'YES'},{"Records.Properties.$":1}).pretty()
    

    回应

    {
        "_id": ObjectId("5859e80591c255c059a3da50"),
        "Records": {
            "Properties": [{
                "Property": {
                    "Name": "YES"
                },
                "value": "1472065148"
            }]
        }
    }
    

    附加部分的更新:

    有几种方法可以解决这个问题。事情可以稍微优化一下,但我会留给你。

    选项 1:

    $map 在传递的条件和每个结果元素中的字段之间应用相等比较,并生成一个包含真假值的数组。 $anyElementTrue 检查此数组并仅当数组中至少有一个真值时才返回真值。匹配阶段以仅包含匹配值为 true 的元素。

    使用系统变量 $$ROOT 保存数据的数据字段。

    完整查询

    db.dataset.aggregate([{
        $unwind: "$Records"
    }, {
        $project: {
            "_id": 0,
            "matched": {
                "$anyElementTrue": {
                    "$map": {
                        "input": "$Records.Properties",
                        "as": "result",
                        "in": {
                            "$and": [{
                                $eq: ["$$result.Property.Name", "LastWrite"]
                            }, {
                                $eq: ["$$result.value", "42"]
                            }]
                        }
                    }
                }
            },
            "data": "$$ROOT"
        }
    }, {
        "$match": {
            "matched": true
        }
    }, {
        $unwind: "$data.Records"
    }, {
        $unwind: "$data.Records.Properties"
    }, {
        $match: {
            "data.Records.Properties.Property.Name": 'YES'
        }
    }, {
        $project: {
            "_id": 0,
            "value": "$data.Records.Properties.value"
        }
    }]).pretty()
    

    选项 2:

    更好的选择(性能优越),所以如果您的驱动程序支持 $redact,请使用此选项。

    与上面的版本类似,但这个版本将项目和比赛阶段合二为一。带有 $redact 的 $cond 说明匹配,当找到匹配时,它会保留完整的树,否则会丢弃它。

    完整查询

    db.dataset.aggregate([{
        $unwind: "$Records"
    }, {
        "$redact": {
            "$cond": [{
                    "$anyElementTrue": {
                        "$map": {
                            "input": "$Records.Properties",
                            "as": "result",
                            "in": {
                                "$and": [{
                                    $eq: ["$$result.Property.Name", "LastWrite"]
                                }, {
                                    $eq: ["$$result.value", "42"]
                                }]
                            }
                        }
                    }
                },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }, {
        $unwind: "$Records.Properties"
    }, {
        $match: {
            "Records.Properties.Property.Name": 'YES'
        }
    }, {
        $project: {
            "_id": 0,
            "value": "$Records.Properties.value"
        }
    }]).pretty()
    

    【讨论】:

    • 谢谢 :) 非常有帮助。
    • 我在数据库中有多个 json 文档,我试图提取 3 个属性,每个 json 具有各自的值。我尝试了第一种方法,它给了我很好的结果,但我不能像使用'for x in find_restuls''print x'之前那样单独打印它们,我可以在其中设置范围。我尝试了第二种方法,首先将将 XML 转换为 json 并将它们导入 Mongo 的脚本,但是当我从数组更改为对象时,'records.append(records)' 函数停止工作,当我使用“更新”它错过了信息。
    • 我对python语言一无所知。这看起来像是属于那里的问题。您可以针对您面临的问题提出另一个问题。
    • 我还有最后一个问题,希望你能帮到你。您提供的第一个答案我已经成功,再次感谢。我希望用这种方法做一些稍微不同的事情。
    • 我还有最后一个问题,希望不要碰运气。您提供的第一个答案我已经成功,再次感谢。我希望使用这种方法来做一些稍微不同的事情。 - 仍然需要与名称关联的值:是(如上) - 我希望首先根据与名称关联的值过滤文档:父母(如下)
    猜你喜欢
    • 2012-07-23
    • 1970-01-01
    • 1970-01-01
    • 2012-06-24
    • 2016-09-05
    • 1970-01-01
    • 2018-11-01
    • 2019-05-17
    • 1970-01-01
    相关资源
    最近更新 更多