I have a document like this:
{
timestamp: ISODate("2013-10-10T23:00:00.000Z"),
values: {
0: 25,
1: 2,
3: 16,
4: 12,
5: 10
}
}
Two questions:
0
from the nested document in values
? 答案 0 :(得分:2)
你真的需要改变你构建文档的方式,因为你现在所拥有的并不好。像你这样的嵌套对象不能在正常的查询操作中“遍历”,因此它们无法有效地搜索“跨键”。
执行此操作的唯一方法是使用$where
的JavaScript评估,这意味着可以使用“无索引”来优化搜索。它也基本上是对集合中每个文档的“强力”匹配:
db.collection.find(function() {
var values = this.values;
return Object.keys(values).some(function(key) {
return values[key] == 2;
});
})
这只是在嵌套键中找到值“2”,以便找出“最大”值是否为“2”,那么你会这样做:
db.collection.find(function() {
var values = this.values;
return Math.max.apply(null, Object.keys(values).map(function(key) {
return values[key];
})) == 2;
})
所以蛮力不好。最好用“值”作为“数组”来构建文档。然后所有本机查询都可以正常工作:
{
"timestamp": ISODate("2013-10-10T23:00:00.000Z"),
"values": [25, 2, 16, 12, 10]
}
现在你可以做到:
db.collection.aggregate([
{ "$match": { "values": 2 } },
{ "$unwind": "$values" },
{ "$group": {
"_id": "$_id",
"timestamp": { "$first": "$timestamp" },
"values": { "$push": "$values" },
"maxVal": { "$max": "$values" }
}},
{ "$match": { "maxVal": 2 } }
])
乍一看似乎更麻烦,但是使用本机运算符而不是JavaScript转换构建它确实会提高效率。它的效率也显着提高,因为现在可以实际搜索“values”数组是否实际上甚至包含“2”作为使用索引的值,而无需在循环代码中测试所有内容。
主要工作是在测试数组的“max”值时完成的,所以即使这不是最明亮的例子,你甚至可以看到普通查询操作如何与JavaScript评估相结合的明显区别现在,让这个过程更快:
db.collection.find({
"values": 2,
"$where": function() {
return Math.max.apply(null,this.values) == 2;
}
})
因此,初始"values": 2
将立即过滤包含“2”的文档的文档,后续表达式仅过滤掉那些数组的“max”值为“2”的文档。
此外,如果您打算定期查询这样的“最大”值,那么最好将此值存储为文档本身的离散字段,如下所示:
{
"timestamp": ISODate("2013-10-10T23:00:00.000Z"),
"values": [25, 2, 16, 12, 10],
"minValue": 2,
"maxValue": 25
}
然后查找“最大值”为2的文档非常简单:
db.collection.find({ "maxValue": 2 })
或所有文件中最大的“最大”:
db.collection.find().sort({ "maxValue": -1 }).limit(1)
甚至同时来自所有文件的“min”和“max”:
db.collection.aggregate([
{ "$group": {
"_id": null,
"minValue": { "$min": "$minValue" },
"maxValue": { "$max": "$maxValue" }
}}
])
在添加新“值”时维护此数据,只需在更新时使用 $min
和 $max
更新运算符文献。所以要在值中添加“26”:
db.collection.update(
{ "timestamp": ISODate("2013-10-10T23:00:00.000Z") },
{
"$push": { "values": 26 },
"$min": { "minValue": 26 },
"$max": { "maxValue": 26 }
}
)
这导致只有$min
或$max
分别小于或大于当前值的调整值。
{
"timestamp": ISODate("2013-10-10T23:00:00.000Z"),
"values": [25, 2, 16, 12, 10, 26],
"minValue": 2,
"maxValue": 26
}
因此,应该清楚地看到结构为什么重要,并且应该避免嵌套对象优先于您想要遍历数据的数组,分析文档本身,或者实际上跨多个文档在一个集合中。