我已经研究了大约一个星期,已经学习了很多关于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})
但要避免价值'与所有其他值处于同一水平,我得到了所有的值结果,而不仅仅是我希望的结果。
有没有办法在匹配查询的对象之后只打印结果对象? "名称" :"是"作为我查询和"价值的对象" :" 1472065148"是我想要打印的对象。
------------------------ ADDITIONAL PART ---------------
以上是一个名称为'的文件。 :'是'我想要追溯的价值观。但是每个文档都有相同的名称:YES'在里面。我想做的是,首先根据不同的名称选择文件。 :' xxxx'以它的价值。例如上面 - 查找名称' :' lastwrite'在检索名称之前检查其值是否为42(因此选择此文档而不选择其他文档)。 :'是'价值(如你给我的答案)。
(如果这是一个新问题,请告诉我,我会将其删除并发布新问题)
答案 0 :(得分:2)
您对现有结构的唯一选择是使用聚合。
db.dataset.aggregate([{
$unwind: "$Records"
}, {
$unwind: "$Records.Properties"
}, {
$match: {
"Records.Properties.Property.Name": 'YES'
}
}, {
$project: {
"_id": 0,
"value": "$Records.Properties.value"
}
}]).pretty()
样本回复
{ "value" : "1472065148" }
假设您能够按如下方式更新结构(为简洁起见,删除了一些字段)。这里的变化是记录不再是一个数组,而只是一个嵌入的文档。
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应用传递的条件与每个结果元素中的字段之间的等于比较,并生成具有true和false值的数组。 $ anyElementTrue检查此数组,并且仅当数组中至少有一个true值时才返回true。匹配阶段仅包含匹配值为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()