我有一个查询,可以在下面的示例数据集中获取minimum query
和maximum query
。在我的案例中,字段名称是动态的,例如product_1
下方,product_2
...
{
"_id" : NumberLong(540),
"product_1" : {
"orderCancelled" : 0,
"orderDelivered" : 6
},
"product_2" : {
"orderCancelled" : 3,
"orderDelivered" : 16
},
"product_3" : {
"orderCancelled" : 5,
"orderDelivered" : 11
}
}
我不知道我如何才能在Mongo中执行此操作,其中字段名称是动态的,意味着将来可能还会创建其他产品product_4
和product_5
同一{ {1}}。
我需要一个查询,它为id
提供最小值,为orderDelivered
提供最大值,例如在上面的文档中,结果将为orderCancelled
& orderDelivered:16
。
谢谢你的任何想法。
答案 0 :(得分:2)
您需要通过更新文档结构来更改它们。您需要使用.forEach
方法循环浏览每个文档,然后$unset
以product_
开头的所有字段名称。在那里,您需要使用$set
更新运算符添加新字段products
,这是一系列产品。话虽如此,您应该使用"bulk"操作来更新文档以获得最高效率
var bulkOp = db.collection.initializeOrderedBulkOp();
var count = 0;
db.collection.find().forEach(function(doc) {
var allproducts = [];
for(var key in doc) {
if(Object.prototype.hasOwnProperty.call(doc, key) && /^product_\d+/.test(key)) {
var product = {};
product["name"] = key;
product["orderCancelled"] = doc[key]["orderCancelled"];
product["orderDelivered"] = doc[key]["orderDelivered"];
allproducts.push(product);
var unsetField = {};
unsetField[key] = "";
bulkOp.find({"_id": doc._id}).update({ "$unset": unsetField });
};
count++;
};
bulkOp.find({"_id": doc._id}).update({
"$set": { "products": allproducts }
});
count++;
if(count % 500 === 0) {
// Execute per 500 operations and re-init
bulkOp.execute();
bulkOp = db.collection.initializeOrderedBulkOp();
}
})
// clean up queues
if(count > 0) {
bulkOp.execute();
}
您的文档现在看起来像这样:
{
"_id" : NumberLong(542),
"products" : [
{
"name" : "product_1",
"orderCancelled" : 0,
"orderDelivered" : 6
},
{
"name" : "product_2",
"orderCancelled" : 3,
"orderDelivered" : 16
},
{
"name" : "product_3",
"orderCancelled" : 5,
"orderDelivered" : 11
}
]
}
然后使用.aggregate()
方法进行聚合查询:
db.collection.aggregate([
{ "$match": { "_id": 542 } },
{ "$unwind": "$products" },
{ "$group": {
"_id": "$_id",
"maxOrderCancelled": { "$max": "$products.orderCancelled"},
"minOrderDelivvered": { "$min": "$products.orderDelivered"}
}}
])
返回:
{ "_id" : NumberLong(542), "maxOrderCancelled" : 5, "minOrderDelivvered" : 6 }
从version 3.2开始,您可以在$project
阶段使用$max
和$min
,这是更好的方法,因为不需要{{3}你的数组首先。
db.collection.aggregate([
{ "$match": { "_id": 542 } },
{ "$project": {
"maxOrderCancelled": {
"$max": {
"$map": {
"input": "$products",
"as": "order",
"in": "$$orc.orderCancelled"
}
}
},
"minOrderDelivered": {
"$min": {
"$map": {
"input": "$products",
"as": "orc",
"in": "$$orc.orderDelivered"
}
}
}
}}
])
哪个收益率:
{ "_id" : NumberLong(542), "maxOrderCancelled" : 5, "minOrderDelivered" : 6 }
答案 1 :(得分:1)
您应该重新构建文档,以便所有产品文档都在一个数组中:
{
"_id": NumberLong(540),
products: [
{
"name": "product_1",
"orderCancelled": 0,
"orderDelivered": 6
},
{
"name": "product_2",
"orderCancelled": 3,
"orderDelivered": 16
},
{
"name": "product_3",
"orderCancelled": 5,
"orderDelivered": 11
}
]
}
然后您就可以发出正常的最大/最小查询:
db.test.aggregate([
{
$match: { "_id" : NumberLong(540) }
},
{
$unwind: "$products"
},
{
$group: {
_id: "$_id",
minDelivered: { $min: "$products.orderDelivered" },
maxCancelled: { $max: "$products.orderCancelled" }
}
}
])