考虑工作订单集合的以下架构。
{"Activity #": "1111111",
"Customer": "Last, First",
"Tenure": "0 Year 2 Months",
"Account #": "0000000",
"lines": [{
"Line#": "line#",
"Product": "product",
"Status": "status",
"price": "price"
},
{
"Line#": "line#",
"Product": "product",
"Status": "status",
"price": "price"
}]}
我可以使用以下查询获取所有已关闭的订单项。
db.workorders.aggregate({$match:{"Status":"Closed"}},{$unwind:"$lines"},{$match:{"lines.Status":"Closed"}},{$project:{lines:1}})
现在让我说我有另一个收藏价格。
{"Product":"product",
"Price":"Price"}
如何通过匹配价格集合中的产品来更新已关闭的行项目价格。
提前致谢。
答案 0 :(得分:1)
因此,尽管您可以使用聚合获得此结果,但问题在于这正是聚合的用途。因此,它用于查询结果。
虽然这样做"过滤"只是"匹配"数组中您需要的项目,下一个问题是您不能更新一次超过一个数组元素。所以为了更新"多个"项目,您唯一的选择是在更新期间替换整个数组。除非你已经拥有了数组的内容,否则你需要获取整个文档。
"第三"你在这里介绍的问题是你需要"查找"另一个集合,以匹配值。简而言之, MongoDB不会加入。那就是。
除非你改变你的架构以适应其他方式,否则你会坚持这个:
db.workorders.find({ "Status": "Closed", "lines.Status": "Closed" })
.forEach(function(order) {
for ( var i = 0; i < order.lines.length; i++ ) {
if ( order.lines[i].Status == "Closed" ) {
var prod = db.product.findOne(
{ "product": order.lines[i].product });
order.lines[i].price = prod.price;
}
}
db.workorders.update(
{ "_id": order._id },
{ "$set": { "lines": order.lines } }
);
})
或者这实际上在您的语言实现中有效。但这是一般的逻辑。
因此,在这种情况下,原始聚合语句对您不太好。即使使用匹配的&#34;工作人员&#34;这个结果有点多余,因为你无论如何都可以查询。
这里有一个用法有助于优化这一点,这就是改变聚合语句以获得您将要查找的唯一产品更新。然后,不是每次匹配产品时调用.findOne()
,而是可以使用聚合到&#34;缓存&#34;的结果。将被击中的产品#34;在更新中。
var prodValues = db.workorders.aggregate([
// Match the order
{ "$match":{ "Status":"Closed" }},
// Unwind the array
{ "$unwind":"$lines" },
// Match only the closed lines
{ "$match" :{ "lines.Status":"Closed" } },
// Group the products
{ "$group": {
"_id": null,
"products": { "$addToSet": "$lines.Product" }
}}
])
然后,您可以将其提供给您的查询产品一次,以便获得&#34;价格缓存&#34;:
var prodCache = {};
db.products.find({ "Product": { "$in": prodValues.result.products } })
.forEach(function(product) {
prodCache[product.Product] = product.price;
});
并使用它代替每次都做一次查找。所以改变这些方面:
if ( order.lines[i].Status == "Closed" )
order.lines[i].price =
prodCache[order.lines[i].Product].price;
所以至少这会给你&#34;一些&#34;从您的汇总声明中受益。
总体而言,当您必须更新阵列中的多个项时,最好更新整个阵列。至少到下一个版本(写作时),你可以在batch updates中完成。
答案 1 :(得分:0)
上面的当前答案包含过时的信息。
Mongo 可以使用$ out更新集合,该集合将查询并输出到您指定的集合,因此,如果您指定要集合的集合,它将对其进行更新。因此,您可以向嵌入式数组添加一个值,然后输出该新集合,从而向数组添加一个新值。
Mongo 可以加入,尽管我会尽可能避免。您可以在汇总中使用$ lookup来从其他集合中获取信息。如果您好奇的话,还可以使用Mongoose并使用其填充功能。注意:您不能将$ out包含在$ lookup管道中,因此请将$ out放在整体汇总的末尾。
您可以通过以下两种方式结合这两个原则:
db.workorders.aggregate({
$match:{"Status":"Closed"}},
{$unwind:"$lines"},
{$match:{"lines.Status":"Closed"}},
{
$lookup:
{
from: Prices,
localField: lines.price,
foreignField: price,
as: lines.price
}
},
{
$lookup:
{
from: Product,
localField: lines.Product,
foreignField: Product,
as: lines.Product
}
},
{ $output: "workorders" } // this will replace your collection with output from aggregate