简体   繁体   English

MongoDB 更新(聚合管道)使用来自嵌套嵌套 Arrays 的值

[英]MongoDB Update (Aggregation Pipeline) using values from nested nested Arrays

I'm trying to update a field (totalPrice) in my document(s) based on a value in a nested, nested array (addOns > get matching array from x number of arrays > get int in matching array[always at pos 2]).我正在尝试根据嵌套的嵌套数组中的值更新我的文档中的字段(totalPrice)(addOns > 从 arrays 的 x 个数中获取匹配数组 > 在匹配数组中获取 int [总是在 pos 2] )。

Here's an example of a document with 2 arrays nested in addOns:这是一个包含 2 个 arrays 嵌套在 addOns 中的文档示例:

{
   "_id": ObjectID('.....'),
   "addOns": [
                ["appleId", "Apples", 2],
                ["bananaID", "Bananas", 1]
             ],
   "totalPrice": 5.7
}

Let's say the price of bananas increased by 20cents, so I need to look for all documents that have bananas in its addOns, and then increase the totalPrice of these documents depending on the number of bananas bought.假设香蕉的价格上涨了 20 美分,所以我需要查找其插件中包含香蕉的所有文档,然后根据购买的香蕉数量增加这些文档的 totalPrice。 I plan on using a updateMany() query using an aggregation pipeline that should roughly look like the example below.我计划使用一个聚合管道来使用 updateMany() 查询,它应该大致类似于下面的示例。 The???这??? should be the number of bananas bought, but I'm not sure how to go about retrieving that value.应该是购买的香蕉数量,但我不确定如何通过 go 检索该值。 So far I've thought of using $unwind, $filter, and $arrayElemAt, but not sure how to use them together.到目前为止,我一直在考虑使用 $unwind、$filter 和 $arrayElemAt,但不确定如何将它们一起使用。 Would appreciate any help!将不胜感激任何帮助!

db.collection('orders').updateMany(
     { $elemMatch: { $elemMatch: { $in: ['bananaID'] } } },
     [
          { $set: {'totalPrice': { $add: ['$totalPrice', { $multiply: [{$toDecimal: '0.2'}, ???] } ] } } }
     ]

I'm not exactly sure whats my mongo version is, but I do know that I can use the aggregation pipeline because I have other updateMany() calls that also use the pipeline without any issues, so it should be (version >= 4.2).我不确定我的 mongo 版本是什么,但我知道我可以使用聚合管道,因为我还有其他 updateMany() 调用也使用管道没有任何问题,所以它应该是(版本> = 4.2) .

** Edit : Thought of this for the???, the filter step seems to work somewhat as the documents are getting updated, but the value is null instead of the updated price. **编辑:为???想到这一点,随着文档的更新,过滤步骤似乎有点工作,但值是 null 而不是更新后的价格。 Not sure why不知道为什么

  1. Filter the '$addOns' array to return the matching nested array.过滤 '$addOns' 数组以返回匹配的嵌套数组。
  2. For the condition, use $eq to check if the element at [0] ('$$this.0') matches the string 'bananaID', and if it does return this nested array.对于条件,使用 $eq 检查 [0] ('$$this.0') 处的元素是否与字符串 'bananaID' 匹配,如果它确实返回此嵌套数组。
  3. Get the array returned from step 1 using $arrayElemAt and position [0].使用 $arrayElemAt 和 position [0] 获取从步骤 1 返回的数组。
  4. Use $arrayElemAt again on the array from step 3 with positon [2] as it is the index of the quantity element在第 3 步中的数组上再次使用 $arrayElemAt,位置为 [2],因为它是数量元素的索引
{ $arrayElemAt: [{ $arrayElemAt: [ { $filter: { input: "$addOns", as:'this', cond: { $eq: ['$$this.0', 'bananaID'] } } } , 0 ] }, 2 ] }

Managed to solve it myself - though only use this if you don't mind the risk of updateMany() as stated by Joe in the question's comments.设法自己解决了这个问题 - 虽然只有在你不介意问题评论中乔所说的 updateMany() 风险的情况下才使用它。 It's very similar to what I originally shared in ** Edit , except you cant use $$this.0 to access elements in the array.它与我最初在 ** Edit中共享的内容非常相似,只是您不能使用$$this.0访问数组中的元素。

Insert this into where the???把这个插入到哪里??? is and it'll work, below this code block is the explanation:是并且它会起作用,在这个代码块下面是解释:

{ $arrayElemAt: [{ $arrayElemAt: [ { $filter: { input: "$addOns", as:'this', cond: { $eq: [{$arrayElemAt:['$$this', 0]}, 'bananaID'] } } } , 0 ] }, 2 ] }
  1. Our array looks like this: [["appleId", "Apples", 2], ["bananaID", "Bananas", 1]]我们的数组如下所示: [["appleId", "Apples", 2], ["bananaID", "Bananas", 1]]
  2. Use $filter to return a subset of our array that only contains the elements that matches our condition - in this case we want the array for bananas.使用 $filter 来返回我们数组的一个子集,它只包含与我们的条件匹配的元素——在这种情况下,我们想要香蕉的数组。 $$this represents each element in input, and we check whether the first element of $$this matches 'bananaID'. $$this代表输入中的每个元素,我们检查$$this的第一个元素是否匹配'bananaID'。
{ $filter: { input: "$addOns", as:'this', cond: { $eq: [{$arrayElemAt:['$$this', 0]}, 'bananaID'] } } }

// how the result from $filter should look like
// [["bananaID", "Bananas", 1]]
  1. Because the nested banana array will always be the first element, we use $arrayElemAt on the result from step 2 to retrieve the element at position 0.因为嵌套的香蕉数组总是第一个元素,所以我们在第 2 步的结果中使用 $arrayElemAt 来检索 position 0 处的元素。
// How it looks like after step 3: ["bananaID", "Bananas", 1]
  1. The last step is to use $arrayElemAt again, except this time we want to retrieve the element at position 2 (quantity of bananas bought)最后一步是再次使用 $arrayElemAt,除了这次我们要检索 position 2 处的元素(购买的香蕉数量)
  2. This is how the final updateMany() query looks like after steps 1-4 are evaluated.这是评估步骤 1-4 后最终 updateMany() 查询的样子。
db.collection('orders').updateMany(
     { $elemMatch: { $elemMatch: { $in: ['bananaID'] } } },
     [
          { $set: {'totalPrice': { $add: ['$totalPrice', { $multiply: [{$toDecimal: '0.2'}, 1] } ] } } }
     ], *callback function code*)

// notice how the ??? is now replaced by the quantity of bananas which is 1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM