【问题标题】:MongoDB: Transform array of objects to array of arraysMongoDB:将对象数组转换为数组数组
【发布时间】:2021-03-11 15:16:23
【问题描述】:

我有一个名为“records”的集合,其中包含以下格式的文档:

{
  "name": "a"
  "items": [
    {
      "a": "5", 
      "b": "1", 
      "c": "2"
    }, 
    {
      "a": "6", 
      "b": "3", 
      "c": "7"
    }
  ]
}

我想保留数据库中的数据(使数据易于阅读和解释)。但我想运行一个查询,以下列形式返回数据:

{
  "name": "a"
  "items": [
    ["5", "1", "2"],
    ["6", "3", "7"],
  ]
}

pymongo 可以做到这一点吗?我知道我可以使用 Python 运行查询并翻译文档,但我想尽可能避免遍历查询结果。

【问题讨论】:

  • 这个Mongo Playground 对你有用吗?
  • 另外,如果它适合您的需要,请不要考虑in: { $toString: "$$item.v" } 表达式;刚刚发现您可以改用in: "$$item.v"
  • @Rfroes87 你成功了!您能否在您的代码中添加一个答案以及对其中发生的事情的一些描述?如果您可以在这种方法的性能考虑方面添加一些 cmets,而不是简单地遍历文档并修改它们,例如使用 Python,我将不胜感激!

标签: mongodb pymongo


【解决方案1】:

我有一个名为“记录”的表

收藏

pymongo 可以做到这一点吗?

是的

任何有关如何解决此问题的指示都会非常有帮助!

我建议您在 MongoDB 查询期间使用 view 来转换您的数据。
通过这种方式,您可以获得转换后的数据,并在需要时将find 应用于已转换的数据。

db.createCollection(
    "view_name",
    {"viewOn": "original_collection_name",
     "pipeline": [{$unwind: "$items"},
                  {$project: {name: 1, items: {$objectToArray: "$items"}}},
                  {$project: {name: 1, items: {$concatArrays: ["$items.v"]}}}, 
                  {$group: {_id: "$_id", name: {$first: "$name"},
                            items: {$push: "$items"}}}]
    }
)

> db.view_name.find({name: "a"})
{ "_id" : ObjectId("5fc3dbb69cb76f866582620f"), "name" : "a", "items" : [ [ "5", "1", "2" ], [ "6", "3", "7" ] ] }

> db.view_name.find({"items": {$in: [["5", "1", "2"]]}})
{ "_id" : ObjectId("5fc3dbb69cb76f866582620f"), "name" : "a", "items" : [ [ "5", "1", "2" ], [ "6", "3", "7" ] ] }

> db.view_name.find()
{ "_id" : ObjectId("5fc3dbb69cb76f866582620f"), "name" : "a", "items" : [ [ "5", "1", "2" ], [ "6", "3", "7" ] ] }

查询:

db.original_collection_name.aggregate([
    {$unwind: "$items"},
    {$project: {name: 1, items: {$objectToArray: "$items"}}}, 
    {$project: {name: 1, items: {$concatArrays: ["$items.v"]}}}, 
    {$group: {_id: "$_id", name: {$first: "$name"}, items: {$push: "$items"}}}])

【讨论】:

    【解决方案2】:

    使用$objectToArray$map 转换:

    // { name: "a", items: [ { a: "5", b: "1", c: "2" }, { a: "6", b: "3", c: "7" } ] }
    db.collection.aggregate([
    
      { $set: { items: { $map: { input: "$items", as: "x", in: { $objectToArray: "$$x" } } } } },
      // {
      //   name: "a",
      //   items: [
      //     [ { k: "a", v: "5" }, { k: "b", v: "1" }, { k: "c", v: "2" } ],
      //     [ { k: "a", v: "6" }, { k: "b", v: "3" }, { k: "c", v: "7" } ]
      //   ]
      // }
    
      { $set: { items: { $map: { input: "$items", as: "x", in: "$$x.v" } } } }
    ])
    // { name: "a", items: [["5", "1", "2"], ["6", "3", "7"]] }
    

    这会将items'元素映射为键/值数组,使得{ field: "value" } 变为[ { k: "field", v: "value" } ]。这样,无论字段名称如何,我们都可以使用v 轻松访问该值,这就是第二个$set 阶段的作用:"$$x.v"

    这样做的好处是避免了诸如 unwind/group 之类的繁重阶段。

    请注意,您也可以将第二个$map 覆盖在第一个中;但这可能不太可读。

    【讨论】:

      猜你喜欢
      • 2021-09-17
      • 2018-10-13
      • 2019-04-13
      • 2018-11-08
      • 2021-05-03
      • 2018-12-04
      相关资源
      最近更新 更多