这很棘手,
我有这个样本文件
[{
_id: '111',
products: [{
_id: 'productId',
items: [{
_id: 'aaa',
quantity: 5
}, {
_id:'bbb',
quantity: 8
}]
}]
}]
现在,当我购买商品时,我需要从商品数组中的第一个减少到第二,第三等的数量减少数量...
这就是说,当我购买一个商品时,我需要在商品数组的第一个元素中减少数量,并且如果要减少的数量超过了,则应该减少第二个商品数组中的剩余数量。 ..等等
例如,如果我购买了3件商品,则它在第一个数组元素中应减去3件商品,并且结果商品数组应为
...
items: [{
_id: 'aaa',
quantity: 2
}, {
_id: 'bbb',
quantity: 8
}]
另一方面,如果我要购买7件商品,则应该减少第一个数组元素中的所有5件商品,然后从第二个元素中删除2件商品,因此最终的数组就像
...
items: [{
_id: 'aaa',
quantity: 0
}, {
_id: 'bbb',
quantity: 6
}]
我尝试过的内容:
我试图像这样使用findOneAndUpdate,只是为了到达items数组,但我不知道我应该如何继续进行item部分。
Shop.findOneAndUpdate(
{ _id: '111', products._id: 'productId' }
)
答案 0 :(得分:1)
尽管MongoDB v4.2(update pipeline)可以实现,您可以在其中基于文档的当前值更新文档。这将非常复杂,因为您实际上没有本地方法来保留局部变量(以跟踪已减去的项数)。您可以使用$reduce
来保留该值,但是由于您已深度嵌套了数据结构,因此看起来非常复杂。如果可以在应用程序层中执行此操作会容易得多,但是如果您的文档在两者之间进行更改,则会遇到并发问题。
建议
$accumulator
和$function
运算符,这些运算符可以保持状态并更灵活地使用JavaScript处理数据$reduce
和$cond
。使用这种方法,您必须使用$reduce
来维护状态,并根据状态应用数量值,因为您具有嵌套的数组结构,所以还必须使用$map
。$merge
聚合阶段,该阶段可让您将聚合管道结果输出到同一集合。更新:我尝试实现#3以显示复杂性。 answer对您其他问题的启发
Shop.updateOne({
"_id": '111', "products._id": "productId" // don't forget to replace "productId"
}, [{
"$set":{
"products":{
"$map":{
"input":"$products", // iterate through products, we can not update inside the array directly as "arrayFilters" update option isn't available in pipeline update
"in":{
"$cond":[
{
"$ne":[
"$$this._id",
"productId" // don't forget to replace "productId"
]
},
"$$this",
{
"$mergeObjects":[
"$$this",
{
"items":{
"$reduce":{
"input":"$$this.items",
"initialValue":{ // initialise accumulator
"acc": 7, // the number you want to subtract
"items":[]
},
"in":{
"acc":{
"$subtract":[
"$$value.acc",
{
"$min":[
"$$this.quantity",
"$$value.acc"
]
}
]
},
"items":{
"$concatArrays":[
"$$value.items",
[
{
"$mergeObjects":[
"$$this",
{
"quantity":{
"$subtract":[
"$$this.quantity",
{
"$min":[
"$$this.quantity",
"$$value.acc"
]
}
]
}
}
]
}
]
]
}
}
}
}
}
]
}
]
}
}
}
}
}, // at this stage, you'll have all information you need, add the next stage only if you want it in the same structure
{
"$set":{
"products":{
"$map":{
"input":"$products",
"in":{
"$cond":[
{
"$ne":[
"$$this._id",
"productId"
]
},
"$$this",
{
"$mergeObjects":[
"$$this",
{
"items":{
"$ifNull":[
"$$this.items.items",
"$$this.items"
]
}
}
]
}
]
}
}
}
}
}
])
更新#2一种“较短”版本,仅需一个阶段,使用数组而不是对象来保持累加器。
Shop.updateOne({
"_id": '111', "products._id": "productId" // don't forget to replace "productId"
}, [
{
"$set": {
"products": {
"$map": {
"input": "$products",
"in": {
"$cond": [
{
"$ne": [
"$$this._id",
"productId" // don't forget to replace "productId"
]
},
"$$this",
{
"$mergeObjects": [
"$$this",
{
"items": {
"$arrayElemAt": [
{
"$reduce": {
"input": "$$this.items",
"initialValue": [
7, // the number you want to subtract
[]
],
"in": [
{
"$subtract": [
{
"$arrayElemAt": [
"$$value",
0
]
},
{
"$min": [
"$$this.quantity",
{
"$arrayElemAt": [
"$$value",
0
]
}
]
}
]
},
{
"$concatArrays": [
{
"$arrayElemAt": [
"$$value",
1
]
},
[
{
"$mergeObjects": [
"$$this",
{
"quantity": {
"$subtract": [
"$$this.quantity",
{
"$min": [
"$$this.quantity",
{
"$arrayElemAt": [
"$$value",
0
]
}
]
}
]
}
}
]
}
]
]
}
]
}
},
1
]
}
}
]
}
]
}
}
}
}
}
])