【问题标题】:Find maximum length of data in keys for the collection查找集合的键中数据的最大长度
【发布时间】:2017-08-01 15:24:06
【问题描述】:
{
  "_id" : ObjectId("59786a62a96166007d7e364dsadasfafsdfsdgdfgfd"),
  "someotherdata" : {
    "place1" : "lwekjfrhweriufesdfwergfwr",
    "place2" : "sgfertgryrctshyctrhysdthc ",
    "place3" : "sdfsdgfrdgfvk",
    "place4" : "asdfkjaseeeeeeeeeeeeeeeeefjnhwklegvds."
  }
}

我的收藏中有数千个。我需要查看所有其他数据并执行以下操作

  1. 检查它是否存在(在某些记录中,我有 place1 而不是 place4)
  2. 查找最长的记录(以字符串长度计)

输出必须看起来像这样(显示最长的字符数)

{   
  place1: 123,
  place2: 12,
  place3: 17
  place4: 445
}

我正在使用 Mongodb 3.2.9,因此无法访问新的聚合函数。但我确实有 Mongodb shell

编辑:要明确的是,我想要整个系列中最长的。因此,可能有 1000 个文档,但整个集合中每个字段只有一个长度最长的结果。

【问题讨论】:

  • 如果无法访问$strLenBytes$strLenCP,则需要使用mapReduce 并使用JavaScript 函数返回每个属性的长度。您是否要求整个集合中的“每个键的最长长度”,或者“只是每个文档的每个键的长度”,甚至输出应该是什么,都不是很清楚。例如,您显示一个包含 4 个可能键且仅输出 3 个键的文档。
  • @NeilLunn 我已经编辑了我的答案

标签: javascript mongodb mapreduce


【解决方案1】:

使用.mapReduce() 来减少每个键的最大值:

db.collection.mapReduce(
  function() {
    emit(null,
      Object.keys(this.someotherdata).map(k => ({ [k]: this.someotherdata[k].length }))
       .reduce((acc,curr) => Object.assign(acc,curr),{})
    );
  },
  function(key,values) {
    var result = {};
    values.forEach(value => {
      Object.keys(value).forEach(k => {
        if (!result.hasOwnProperty(k))
          result[k] = 0;
        if ( value[k] > result[k] )
          result[k] = value[k];
      });
    });
    return result;
  },
  { 
    "out": { "inline": 1 },
    "query": { "someotherdata": { "$exists": true } }
  }
)

它基本上为每个文档发出子文档路径中存在的每个键的"length",然后在“减少”中,实际上只返回每个键的最大"length"

请注意,在mapReduce 中,您需要输出与输入相同的结构,因为它处理大量文档的方式是逐步“减少”批次。这就是为什么我们以数字形式emit,就像"reduce" 函数一样。

在问题中显示的文档中提供此输出。当然,当您拥有更多文档时,它是集合中所有文档的“最大值”。

   {
        "_id" : null,
        "value" : {
            "place1" : 25.0,
            "place2" : 26.0,
            "place3" : 13.0,
            "place4" : 38.0
        }
    }

对于感兴趣的人,问题的上下文实际上是他们无法使用 MongoDB 3.4 的功能。但是要在功能可用的情况下使用.aggregate() 做同样的事情:

db.collection.aggregate([
  { "$match": { "someotherdata": { "$exists": true } } },
  { "$project": {
    "_id": 0,
    "someotherdata": {
      "$map": { 
        "input": { "$objectToArray": "$someotherdata" },
        "as": "s",
        "in": { "k": "$$s.k", "v": { "$strLenCP": "$$s.v" } }
      }
    }
  }},
  { "$unwind": "$someotherdata" },
  { "$group": {
     "_id": "$someotherdata.k",
     "v": { "$max": "$someotherdata.v" }    
  }},
  { "$sort": { "_id": 1 } },
  { "$group": {
    "_id": null,
    "data": {
      "$push": { "k": "$_id", "v": "$v" }
    }    
  }},
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": "$data"   
    } 
  }}
])

同样的输出:

{
    "place1" : 25,
    "place2" : 26,
    "place3" : 13,
    "place4" : 38
}

【讨论】:

  • 当我在 ROBO 3T mongo shell 中运行时,它显示“错误:第 6 行:意外令牌;”
  • @32423hjh32423 我的坏。缺少括号。
  • 说执行脚本失败。错误:map reduce 失败:{ "ok" : 0, "errmsg" : "TypeError: this.someotherdata[k] is null :\n_funcs1/
  • @32423hjh32423 这个字段实际上叫"someotherdata"吗?因为这是你的问题。如果您的数据与您在问题中的数据不同,那么这些变化是在而不是回答的人身上。我可以添加一个$exists 来丢弃不存在该字段的文档,但使用正确的命名取决于您。
  • 我了解您提到的命名问题,我已更改名称,但已对此进行了补偿。这只是对现有内容的直接交换。我认为 $exists 会很有用,因为我认为这就是它失败的原因,因为集合中的项目之间存在差异。谢谢
【解决方案2】:

使用cursor.forEach 遍历集合。 跟踪最长的位置n 值(从 -1 开始,发现更大时更新)。使用print()printjson() 打印出值

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 1970-01-01
    • 1970-01-01
    • 2013-08-22
    • 1970-01-01
    • 2022-01-01
    • 2013-05-06
    相关资源
    最近更新 更多