Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mongodb 如何迭代命名键并获取结果_Mongodb_Mongodb Query_Aggregation Framework - Fatal编程技术网

Mongodb 如何迭代命名键并获取结果

Mongodb 如何迭代命名键并获取结果,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,我正在mongo db中查询嵌套的Json,示例数据结构如下所示: { "_id" : ObjectId("5bf159cc6bf6ab0ac374f80c"), "name" : "Jack", "age" : "30", "info" : { "0" : { "status" : "true", "name" : "luffy" }, "1" : {

我正在mongo db中查询嵌套的Json,示例数据结构如下所示:

{
    "_id" : ObjectId("5bf159cc6bf6ab0ac374f80c"),
    "name" : "Jack",
    "age" : "30",
    "info" : {
        "0" : {
            "status" : "true",
            "name" : "luffy"
        },
        "1" : {
            "status" : "true",
            "name" : "sanji"
        },
        "2" : {
            "status" : "false",
            "name" : "zoro"
        }
    }
}

/* 2 */
{
    "_id" : ObjectId("5bf15f286bf6ab0ac374f8ed"),
    "name" : "Mack",
    "age" : "33",
    "info" : {
        "0" : {
            "status" : "true",
            "name" : "naruto"
        },
        "1" : {
            "status" : "true",
            "name" : "sakura"
        },
        "2" : {
            "status" : "false",
            "name" : "sasuke"
现在我想做的是查询并获取那些状态为“true”的结果。通过谷歌搜索,我了解了如何查询嵌套文档,并给出了一个示例

query:db.getCollection('test').find({“info.0.status”:“true”})

但是,正如您从上面的查询中所知道的,该查询将只从“0”数组中获取适当的结果,如何让查询遍历数组并返回“status”文档:“true”。此外,我是Mongodb的新手,请忽略任何错误

注意:其中一位用户告诉我应该如下所示重新构建数据结构,然后使用$filter操作符:

[
  {
    "_id": ObjectId("5bf159cc6bf6ab0ac374f80c"),
    "name": "Jack",
    "age": "30",
    "info": [
      {
        "status": "true",
        "name": "luffy"
      },
      {
        "status": "true",
        "name": "sanji"
      },
      {
        "status": "false",
        "name": "zoro"
      }
    ]
  },
  {
    "_id": ObjectId("5bf15f286bf6ab0ac374f8ed"),
    "name": "Mack",
    "age": "33",
    "info": [
      {
        "status": "true",
        "name": "naruto"
      },
      {
        "status": "true",
        "name": "sakura"
      },
      {
        "status": "false",
        "name": "sasuke"
      }
    ]
  }
]

但是,我不知道如何按照用户展示的方式重新构建我的结构。我还有什么其他策略可以使用吗?

一般问题的底线是不要尝试以这种形式“查询”,而是接受建议并重写数据。但是有不同的方法来记录

重写收藏 正如已经告诉您的,最好重新建模集合,使其成为真实的“数组”,而不是带有命名键的“对象”

一般情况实际上是“迭代”集合项并重写它们:

var updates = [];
db.getCollection('test').find().forEach(doc => {
  var info = Object.keys(doc.info).map(k => 
    Object.assign({}, doc.info[k], { status: doc.info[k].status === "true" }) );

  updates.push({
    "updateOne": {
      "filter": { "_id": doc._id },
      "update": { "$set": { "doc.info": info } }
    }
  });

  if (updates.length >= 1000) {
    db.getCollection('test').bulkWrite(updates);
    updates = [];
  }

});

if (updates.length >= 0) {
  db.getCollection('test').bulkWrite(updates);
  updates = [];
}
或者编写一个全新的集合:

db.getCollection('test').aggregate([
  { "$addFields": {
    "info": {
      "$map": {
        "input": { "$objectToArray": "$info" },
        "in": {
          "$mergeObjects": [
            "$$this.v",
            { "status": { "$toBool": "$$this.v.status" }
          ]
        }
      }
    }
  }},
  { "$out": "newtest" }
])
最基本的依赖点是,您是否能够容忍“新集合”,并且实际上具有类似MongoDB版本的功能

即使在“更新”时,通常也会建议您(尤其是在生产中)采用来自的方法,因为使用替换整个属性是“暴力”的,对于生产来说不安全。很好,不过只需在您自己的系统上进行测试

完成这两种表格中的任何一种后,您基本上只能对
为true
的匹配项进行搜索,如下所示:

collection.aggregate([
  // Finds valid "documents" 
  { "$match": { "info.status": true } },
  // "filters" the array content
  { "$addFields": {
    "info": {
      "$filter": { "input": "$info", "cond": "$$this.status" }
    }
  }}
])
查询到位 当然,您实际上可以使用当前的文档结构进行查询,但不建议使用

collection.aggregate([
  // Match on transformed object
  { "$match": {
    "$expr": {
      "$gt": [
        { "$size": {
          "$filter": {
            "input": {
              "$map": {
                "input": { "$objectToArray": "$info" },
                "in": "$$this.v"
              }
            },
            "cond": { "$toBool": "$$this.status" }
          }
        }},
        0
      ]
    }
  }},
  // Transform remaining objects
  { "$addFields": {
    "info": {
      "$filter": {
        "input": {
          "$map": {
            "input": { "$objectToArray": "$info" },
            "in": "$$this.v"
          }
        },
        "cond": { "$toBool": "$$this.status" }
      }
    }
  }}
])
或者甚至在中使用JavaScript表达式,当然不支持在从服务器检索之前实际“过滤”结果内容:

collection.find({
  "$where": function() {
    return Object.keys(this.info).map( k => this.info[k])
      .some(e => e.status === "true")
  }
})
在服务器上使用JavaScript更改文档的唯一方法是
mapReduce
,当然它有自己的特定格式:

collection.mapReduce(
  function() {
    var id = this._id;
    delete this._id;
    this.info = Object.keys(this.info)
      .map(k => this.info[k])
      .filter(o => o.status === "true")
    emit(id,this);
  },
  function() {},
  {
    "out": { "inline": 1 },
    "query": {
      "$where": function() {
        return Object.keys(this.info).map( k => this.info[k])
          .some(e => e.status === "true")
      }
    }
  }
)
无论哪种情况,这些都是非常“可怕”的,因为它们基本上依赖于在应用匹配条件之前将每个文档转换为实际的“数组”形式。另一方面,重写集合实际上允许事先完成该工作,从而删除此类计算,并允许指定一个参数,以加快实际查询结果的速度



简而言之,重写它,不要“查询”它当前的状态,因为在跨文档查询时,数据库并没有真正针对“命名键”进行优化。

“我不知道如何重新构建我的结构…”-你到底不“了解”什么?你需要具体说明你不理解的内容和实际问题是什么。“还有其他策略吗…”-不,不是真的。在不牺牲性能的情况下,这正是我们建议您进行重组的原因。那么问题是什么呢?或者我们只是向您指出与您目前展示的内容重复的现有答案?几天前我刚开始使用mongodb,我不知道如何重新构建我的结构(如果可能,使用直接查询)。如果没有其他可行的技术,您能帮我重新构建数据结构吗?谢谢,我一定会尝试重写集合并让您知道。另外,我在哪里可以更好地了解Mongodb函数,比Mongodb文档更详细的内容?@AustinJoy除了链接的文档示例之外,这些示例实际上并不“完全糟糕”,你可以尝试阅读这个网站上已经给出的许多答案。这就是为什么我们在这里回答问题,你知道:)是的,当我试图重写该文件时,我发现了一个错误“\u id”没有定义,我遗漏了什么愚蠢的东西吗?@AustinJoy My Bad。“打字错误”。应该是
doc.\u id
而不仅仅是
\u id
。看看变化。还要注意像
“true”
这样的值作为“字符串”转换为实际的布尔值
true
,我之前也匆忙错过了。感谢您花时间帮助我理解:)