Pymongo 查询过滤版本化数据
Pymongo Query Filtering a versioned data
这是来自我的数据库的示例数据:
{'data':
[{'is_active': True, 'printer_name': 'A', 'vid': 14510},
{'is_active': True, 'printer_name': 'Changed A', 'vid': 14511}
]
},
{'data':
[{'is_active': False, 'printer_name': 'B', 'vid': 14512}]
}
这里的vid
字段就是version id
。每当编辑记录时,修改后的数据都会被推送到列表中,因此它的视频比旧版本高。
现在我想定义一个名为 get_all_active_printers
的方法,它 return 所有带有 is_active :True
的打印机
这是我的尝试,但它 return 两台打印机都不应该 return 打印机 B
def get_all_active_printers():
return printers.find(
{'data.is_active': True}, {"data": {"$slice": -1}, '_id': 0, 'vid': 0})
我的查询有什么问题?
编辑 1 以回应 WanBachtiar
的评论
这是使用命令 print([c for c in get_all_active_printers()])
的实际输出
[{'data': [{'printer_name': 'Changed A', 'vid': 1451906336.6602068, 'is_active': True, 'user_id': ObjectId('566bbf0d680fdc1ac922be4c')}]}, {'data': [{'printer_name': 'B', 'vid': 1451906343.8941162, 'is_active': False, 'user_id': ObjectId('566bbf0d680fdc1ac922be4c')}]}]
正如您在实际输出中看到的那样 - 打印机 B
的 is_active
值为 False,但 get_all_active_printers
仍然 returns B
这是我的版本详细信息:
- Python 3.4.3
- pymongo 3.2
- mongodb2.4.9
在 Ubuntu 14.04,如果重要的话。
编辑 2
注意到另一个问题。查询是 returning vid
字段,即使在投影中明确提到了 'vid': 0
。
* 编辑 3*
我不确定你说的是什么意思
"make sure that there is no other documents for {'printer_name': 'B'}"
。是的,第二个数据(在打印机 B 上)有第二行。那是第一个数据 - 当字段 is_active
为 true
时创建打印机时。后来就变成了false
。这是数据库的快照:
但我想过滤最新数据,因为旧数据仅用于保留审计线索。
如果我将 'data.is_active': True
移动到以下代码中的投影:
def get_all_active_printers():
return printers.find(
{}, {'data': {'$slice': -1}, 'data.is_active': True, '_id': 0, 'vid': 0})
我收到以下错误消息:
pymongo.errors.OperationFailure: database error: You cannot currently
mix including and excluding fields. Contact us if this is an issue.
那么如何根据上面的快照根据最新数据进行过滤?对不起,如果我的问题之前没有说清楚。
感谢您澄清问题。
所以你想查询只有最新元素 is_active: True
.
的文档
不幸的是,在您的情况下,find({'data.is_active': True})
会找到包含任何 data
元素和 is_active:True
的所有文档,而不仅仅是数组中的最后一个元素。此外,在不知道数组长度的情况下,您无法使用 array.i
语法引用数组的最后一个元素。
然而还有其他ways/alternatives:
- 使用 $push, $each and $position to insert new elements to the front of the array. Mongo Shell 示例更新:
/* When updating */
db.printers.update(
/* Filter document for printer B */
{"data.printer_name": 'B'},
/* Push a new document to the front of the array */
{"$push": {
"data": {
$each: [{'is_active': false, 'printer_name': "B", 'vid': 14513 }],
$position: 0
}
}
}
);
/* When querying now you know that the latest one is on index 0 */
db.printers.find(
{"data.0.is_active": true},
{"data": { $slice: 1} }
);
请注意,$position 在 MongoDB v2.6 中是新的。
- 使用MongoDBaggregation to $unwind the array, $group then $match进行筛选。例如:
db.printers.aggregate([
{$unwind: '$data' },
{$sort: { 'data.vid' : 1 } },
{$group: {
'_id': { 'printer_name' : '$data.printer_name', id:'$_id' },
'vid': { $max: '$data.vid' },
'is_active' : { $last: '$data.is_active' }
}
},
{$match:{"is_active": true}}
]);
re-consider 文档架构可能对您有益。例如,与其拥有文档数组,不如考虑将它们扁平化以便于查询。
{'is_active': true, 'printer_name': 'A', 'vid': 14512}
{'is_active': false, 'printer_name': 'B', 'vid': 14513}
有关不同版本跟踪架构设计的更多示例和讨论,请参阅以下博客文章:
也是关于模式设计的有用参考:Data Modeling Introduction。
The query is returning vid field, even though have clearly mentioned
'vid': 0 in the projection.
您可以使用 "data.vid": 0
而不是 vid:0
来隐藏它。
If i move 'data.is_active': True to the projections as in the following code... I get the following error message.
您必须遵守投影规则。有关预测的更多信息,请参阅 projecting fields from query results。
如果您正在开始一个新项目,我建议您使用 MongoDB 的最新稳定版本,目前是 v3.2.0。
此致,
万.
这是来自我的数据库的示例数据:
{'data':
[{'is_active': True, 'printer_name': 'A', 'vid': 14510},
{'is_active': True, 'printer_name': 'Changed A', 'vid': 14511}
]
},
{'data':
[{'is_active': False, 'printer_name': 'B', 'vid': 14512}]
}
这里的vid
字段就是version id
。每当编辑记录时,修改后的数据都会被推送到列表中,因此它的视频比旧版本高。
现在我想定义一个名为 get_all_active_printers
的方法,它 return 所有带有 is_active :True
这是我的尝试,但它 return 两台打印机都不应该 return 打印机 B
def get_all_active_printers():
return printers.find(
{'data.is_active': True}, {"data": {"$slice": -1}, '_id': 0, 'vid': 0})
我的查询有什么问题?
编辑 1 以回应 WanBachtiar
的评论这是使用命令 print([c for c in get_all_active_printers()])
[{'data': [{'printer_name': 'Changed A', 'vid': 1451906336.6602068, 'is_active': True, 'user_id': ObjectId('566bbf0d680fdc1ac922be4c')}]}, {'data': [{'printer_name': 'B', 'vid': 1451906343.8941162, 'is_active': False, 'user_id': ObjectId('566bbf0d680fdc1ac922be4c')}]}]
正如您在实际输出中看到的那样 - 打印机 B
的 is_active
值为 False,但 get_all_active_printers
仍然 returns B
这是我的版本详细信息:
- Python 3.4.3
- pymongo 3.2
- mongodb2.4.9
在 Ubuntu 14.04,如果重要的话。
编辑 2
注意到另一个问题。查询是 returning vid
字段,即使在投影中明确提到了 'vid': 0
。
* 编辑 3*
我不确定你说的是什么意思
"make sure that there is no other documents for {'printer_name': 'B'}"
。是的,第二个数据(在打印机 B 上)有第二行。那是第一个数据 - 当字段 is_active
为 true
时创建打印机时。后来就变成了false
。这是数据库的快照:
但我想过滤最新数据,因为旧数据仅用于保留审计线索。
如果我将 'data.is_active': True
移动到以下代码中的投影:
def get_all_active_printers():
return printers.find(
{}, {'data': {'$slice': -1}, 'data.is_active': True, '_id': 0, 'vid': 0})
我收到以下错误消息:
pymongo.errors.OperationFailure: database error: You cannot currently mix including and excluding fields. Contact us if this is an issue.
那么如何根据上面的快照根据最新数据进行过滤?对不起,如果我的问题之前没有说清楚。
感谢您澄清问题。
所以你想查询只有最新元素 is_active: True
.
不幸的是,在您的情况下,find({'data.is_active': True})
会找到包含任何 data
元素和 is_active:True
的所有文档,而不仅仅是数组中的最后一个元素。此外,在不知道数组长度的情况下,您无法使用 array.i
语法引用数组的最后一个元素。
然而还有其他ways/alternatives:
- 使用 $push, $each and $position to insert new elements to the front of the array. Mongo Shell 示例更新:
/* When updating */
db.printers.update(
/* Filter document for printer B */
{"data.printer_name": 'B'},
/* Push a new document to the front of the array */
{"$push": {
"data": {
$each: [{'is_active': false, 'printer_name': "B", 'vid': 14513 }],
$position: 0
}
}
}
);
/* When querying now you know that the latest one is on index 0 */
db.printers.find(
{"data.0.is_active": true},
{"data": { $slice: 1} }
);
请注意,$position 在 MongoDB v2.6 中是新的。
- 使用MongoDBaggregation to $unwind the array, $group then $match进行筛选。例如:
db.printers.aggregate([
{$unwind: '$data' },
{$sort: { 'data.vid' : 1 } },
{$group: {
'_id': { 'printer_name' : '$data.printer_name', id:'$_id' },
'vid': { $max: '$data.vid' },
'is_active' : { $last: '$data.is_active' }
}
},
{$match:{"is_active": true}}
]);
re-consider 文档架构可能对您有益。例如,与其拥有文档数组,不如考虑将它们扁平化以便于查询。
{'is_active': true, 'printer_name': 'A', 'vid': 14512}
{'is_active': false, 'printer_name': 'B', 'vid': 14513}
有关不同版本跟踪架构设计的更多示例和讨论,请参阅以下博客文章:
也是关于模式设计的有用参考:Data Modeling Introduction。
The query is returning vid field, even though have clearly mentioned 'vid': 0 in the projection.
您可以使用 "data.vid": 0
而不是 vid:0
来隐藏它。
If i move 'data.is_active': True to the projections as in the following code... I get the following error message.
您必须遵守投影规则。有关预测的更多信息,请参阅 projecting fields from query results。
如果您正在开始一个新项目,我建议您使用 MongoDB 的最新稳定版本,目前是 v3.2.0。
此致,
万.