Mongodb Mongoose-如何增量减去/减少另一个子文档数组中的子文档数组中的值

Mongodb Mongoose-如何增量减去/减少另一个子文档数组中的子文档数组中的值,mongodb,mongoose,aggregation-framework,Mongodb,Mongoose,Aggregation Framework,这个很棘手 我有这个样本文件 [{ _id: '111', products: [{ _id: 'productId', items: [{ _id: 'aaa', quantity: 5 }, { _id:'bbb', quantity: 8 }] }] }] 现在,当我购买一件物品时,我需要将数量从物品数组中的第一件减少到第二件、第三件等等 也就是说,当我购买一件物品时,我需要在物品数组的第一个元素

这个很棘手

我有这个样本文件

[{
  _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数组,但我不知道应该如何继续使用items部分

        Shop.findOneAndUpdate(
            { _id: '111', products._id: 'productId' }
        )

尽管这在MongoDB v4.2()中是可能的,您可以根据文档的当前值更新文档。这将是非常复杂的,因为您实际上没有一种本地方法来保存局部变量(跟踪您已经减去了多少项)。您可以使用来保留该值,但它看起来非常复杂,因为您有深度嵌套的数据结构。如果您可以在应用程序层中执行,那么会容易得多,但是如果您的文档在应用程序层和应用程序层之间发生更改,则会出现并发性问题

建议

  • 更改您的数据结构,使其更平坦,可能将其分为多个集合。很难在嵌套较深的项目中进行更新
  • 等待MongoDB v4.4,在那里您可以使用和运算符来保持状态,并且可以更灵活地使用JavaScript处理数据
  • 使用MongoDB v4.2以及和。使用这种方法,您必须使用
    $reduce
    维护状态,并根据状态应用数量值,因为您有嵌套的数组结构,因此也必须使用
  • 如上所述,您可以实现对文档的查询、在应用程序中进行更新并将更改放回MongoDB,但您必须确保在读写之间没有试图更新文档的并发操作
  • 更新:另一个解决方案是等待v4.4聚合阶段,它允许您将聚合管道结果输出到同一个集合
  • 更新:我尝试实现了#3以显示复杂性。关于你的另一个问题,从一篇文章中得到的启示

    Shop.updateOne({
    _id:'111',“products._id:“productId”//别忘了替换“productId”
    }, [{
    “$set”:{
    “产品”:{
    “$map”:{
    “输入”:“$products”,//遍历产品,我们不能直接在数组内部更新,因为“arrayFilters”更新选项在管道更新中不可用
    “在”:{
    “$cond”:[
    {
    “$ne”:[
    “$$this.\u id”,
    productId//别忘了替换“productId”
    ]
    },
    “$$this”,
    {
    “$mergeObjects”:[
    “$$this”,
    {
    “项目”:{
    “$reduce”:{
    “输入”:“$$this.items”,
    “initialValue”:{//初始化累加器
    “acc”:7,//要减去的数字
    “项目”:[]
    },
    “在”:{
    “行政协调会”:{
    “$subtract”:[
    “$$value.acc”,
    {
    “$min”:[
    “$$this.quantity”,
    “$$value.acc”
    ]
    }
    ]
    },
    “项目”:{
    “$concatarray”:[
    “$$value.items”,
    [
    {
    “$mergeObjects”:[
    “$$this”,
    {
    “数量”:{
    “$subtract”:[
    “$$this.quantity”,
    {
    “$min”:[
    “$$this.quantity”,
    “$$value.acc”
    ]
    }
    ]
    }
    }
    ]
    }
    ]
    ]
    }
    }
    }
    }
    }
    ]
    }
    ]
    }
    }
    }
    }
    },//在这一阶段,您将获得所需的所有信息,仅当您希望下一阶段位于同一结构中时才添加它
    {
    “$set”:{
    “产品”:{
    “$map”:{
    “输入”:“$products”,
    “在”:{
    “$cond”:[
    {
    “$ne”:[
    “$$this.\u id”,
    “产品ID”
    ]
    },
    “$$this”,
    {
    “$mergeObjects”:[
    “$$this”,
    {
    “项目”:{
    “$ifNull”:[
    “$$this.items.items”,
    “$$this.item”