MongoDB 我们不知道对象中的键的对象中所有值的总和

MongoDB sum of all values in an object where we do not know the keys in the object

示例文档 1

{
    "site": "xyz.com",
    "Reg_NumReviews": {
        "value1": "194",
        "value53": "3,570"
    },
    "Reg_Score": {
        "value1": "3.24",
        "value53": "1.9"
    }
}

修改后需要的文档

{
    "site": "xyz.com",
    "Reg_NumReviews": {
        "value1": "194",
        "value53": "3,570"
    },
    "Reg_Score": {
        "value1": "3.24",
        "value53": "1.9"
    },
    "Total_reviews" : "3764"
    "Average_score" : 1.97
    
}

示例文档 2

{
    "site": "werw.com",
    "Reg_NumReviews": {
        "value1": "194",
        "value33": "2014",
        "value5": "234"
    },
    "Reg_Score": {
        "value1": "2.24",
        "value33": "3.9",
        "value33": "3",
    }
}

修改后需要的文档

{
    "site": "werw.com",
    "Reg_NumReviews": {
        "value1": "194",
        "value33": "2014",
        "value5": "234"
    },
    "Reg_Score": {
        "value1": "2.24",
        "value33": "3.9",
        "value5": "3",
    },
    "Total_reviews" : "2442"
    "Average_score" : "3.68"
    
}

我试过的代码是以下代码的变体。

db.SiteData.update({"site": "xyz.com" }, 
[ {"$set": { "Total_reviews" : 
  {"$sum" : {"$regex" : /Reg_NumReviews.\.*/} }}}],
  {upsert:true})
    

如果用文字来形容的话:

  1. 找到站点与必要模式匹配的文档。
  2. 检查 Reg_NumReviews 是对象中的键。如果是,则开始设置操作。将所有键值对的值求和,赋值为Total_reviews.
  3. 进入下一个操作,稍微复杂一些。在 Reg_NumReviews 和 Reg_Scores 中找到匹配的键并将它们相乘。将所有这些值相加并除以 Total_reviews,分配为 Average_score.

编辑 澄清第3步 例如在文件二

效果为:

Average_score = 
  (   
    ( Reg_NumReviews.value1 * RegScore.value1 ) + 
    ( Reg_NumReviews.value33 * RegScore.value33 ) +
    ( Reg_NumReviews.value5 * RegScore.value5 )  
  ) /  Total_reviews 

如果您使用的是 Mongo 版本 4.4+,您可以使用此更新,它使用 $objectToArray, then for each it sums them up accordingly, the reason we require v4.4 is due to the usage of $replaceAll 转换字段,用于从数字字符串中删除 , 以允许Mongo 将其转换为数字。

如果您使用的是较小的 Mongo 版本,您仍然可以获得相同的结果,您只需使用不同的方法删除 ,,例如使用 $split , 作为分隔符,然后 $concat 重建字符串。

db.collection.updateMany(
{
  "site": "xyz.com"
},
[
  {
    "$set": {
      "Total_reviews": {
        $sum: {
          $map: {
            input: {
              $objectToArray: "$Reg_NumReviews"
            },
            as: "datum",
            in: {
              $toLong: {
                $replaceAll: {
                  input: "$$datum.v",
                  find: ",",
                  replacement: ""
                }
              }
            }
          }
        }
      },
      Average_score: {
        $avg: {
          $map: {
            input: {
              $objectToArray: "$Reg_Score"
            },
            as: "datum",
            in: {
              $toDouble: "$$datum.v"
            }
          }
        }
      }
    }
  }
])

Mongo Playground ---- 编辑 -----

假设 Reg_scoreReg_NumReviews 具有相同数量的键,您可以使用 $zip 来计算您的最后一个要求,如下所示:

db.collection.updateMany(
{
  "site": "xyz.com"
},
[
  {
    $set: {
      tmpReviews: {
        $map: {
          input: {
            $objectToArray: "$Reg_NumReviews"
          },
          as: "datum",
          in: {
            $toLong: {
              $replaceAll: {
                input: "$$datum.v",
                find: ",",
                replacement: ""
              }
            }
          }
        }
      },
      tmpScores: {
        $map: {
          input: {
            $objectToArray: "$Reg_Score"
          },
          as: "datum",
          in: {
            $toDouble: "$$datum.v"
          }
        }
      }
    }
  },
  {
    "$set": {
      "Total_reviews": {
        $sum: "$tmpReviews"
      },
      Average_score: {
        $avg: "$tmpScores"
      },
      New_complicated_field: {
        $divide: [
          {
            $sum: {
              $map: {
                input: {
                  $zip: {
                    inputs: [
                      "$tmpReviews",
                      "$tmpScores"
                    ]
                  }
                },
                as: "zipped",
                in: {
                  $multiply: [
                    {
                      $arrayElemAt: [
                        "$$zipped",
                        0
                      ]
                    },
                    {
                      $arrayElemAt: [
                        "$$zipped",
                        1
                      ]
                    }
                  ]
                }
              }
            }
          },
          {
            $sum: "$tmpReviews"
          }
        ]
      }
    }
  },
  {
    $unset: {
      tmpReviews: 1,
      tmpScores: 1
    }
  }
])

Mongo Playground