【问题标题】:Mongodb Array and object got mixed up inside arrayMongodb 数组和对象在数组中混淆了
【发布时间】:2021-11-17 01:50:18
【问题描述】:

我在 mongodb 中有以下文档,其中 Grades 键是一个包含对象和数组组合的数组。我的数据库中有几条这样的记录。我想更新数组并将其作为所有此类记录的对象。如何通过更新查询来实现这一点?

 {
        _id: 4,
        grades: [
           { grade: 80, mean: 75, std: 8 },
           { grade: 85, mean: 90, std: 5 },
           [{ grade: 85, mean: 85, std: 8 }]
        ]
      }

预期输出:

 {
        _id: 4,
        grades: [
           { grade: 80, mean: 75, std: 8 },
           { grade: 85, mean: 90, std: 5 },
           { grade: 85, mean: 85, std: 8 }
        ]
      }

【问题讨论】:

  • 你的目标不是很清楚。你的意思是说,你想转换“grades”数组中的最后一项——把它从一个数组本身变成一个对象?
  • 是的。想要将“等级”中存在的数组类型转换为对象。
  • 您是想获取特定形状的数据(即将嵌套数组动态转换为文档)还是需要实际更改静态数据的形状(在数据库)?
  • 需要改变DB中文档的形状。 Mongo 3.4版
  • 您需要一次更改所有文档,还是可以使用模式版本控制模式(在您的应用程序中遇到它们时更改它们)? - mongodb.com/blog/post/…

标签: arrays mongodb object


【解决方案1】:

MongoDB 3.4 中使用单个更新查询是不可能做到这一点的,

1) 您可以在循环中执行 2 个查询,第一次查找和第二次更新,您可以在 mongo shell 或任何 MongoDB 编辑器中执行:

  • find() 查询项目要求字段并循环结果
  • for 循环 grades 数组
  • 检查条件 Grades 元素是否为数组,然后 concat 否则返回相同
  • update() 查询更新新的grades 数组
db.getCollection('grades').find({}, { grades: 1 }).forEach(function (doc) {
    var grades = [];
    for(var i = 0; i < doc.grades.length; i++) {
        if (Array.isArray(doc.grades[i])) {
            grades = grades.concat(doc.grades[i]);
        }
        else {
            grades.push(doc.grades[i]);
        }
    }
    // update
    db.getCollection('grades').update(
        { _id: doc._id }, 
        { $set: { grades: grades } }
    )
})

2) 您可以尝试聚合查询并使用单个查询将更新的结果导出到新集合中,

  • $reduce 迭代 grades 数组的循环
  • $type获取元素的数据类型
  • $concatArrays 连接多个数组
  • $cond 检查条件,如果元素类型是数组,则直接连接两个数组,否则将数组连接到数组中
  • $out 在新集合中导出集合
db.collection.aggregate([
  {
    $addFields: {
      grades: {
        $reduce: {
          input: "$grades",
          initialValue: [],
          in: {
            $cond: [
              { $eq: [{ $type: "$$this" }, "array"] },
              { $concatArrays: ["$$value", "$$this"] },
              { $concatArrays: ["$$value", ["$$this"]] }
            ]
          }
        }
      }
    }
  },
  { $out: "collection name" }
])

Playground


3) 使用 update with aggregation pipeline 查询的替代选项MongoDB 4.2

db.collection.updateMany({},
  [{
    $set: {
      grades: {
        $reduce: {
          input: "$grades",
          initialValue: [],
          in: {
            $cond: [
              { $eq: [{ $type: "$$this" }, "array"] },
              { $concatArrays: ["$$value", "$$this"] },
              { $concatArrays: ["$$value", ["$$this"]] }
            ]
          }
        }
      }
    }
  }]
)

Playground

【讨论】:

  • 这假设嵌套数组只有一个文档条目。不确定这是不是真的。
  • 好吧,至少我们可以用它的 id 更新一些具体提到的记录吗?
  • @Jagadeesh 更新了 3.4 的第一种方法。第二种方法适用于 4.2。我是的,您可以在 find 方法的查询部分中提供 id。
猜你喜欢
  • 2012-08-13
  • 2022-11-22
  • 2014-05-18
  • 2018-07-28
  • 2012-01-26
  • 1970-01-01
  • 2016-03-20
  • 1970-01-01
  • 2017-09-20
相关资源
最近更新 更多