【问题标题】:Add minimum available key to dictionary MongoDB向字典 MongoDB 添加最小可用键
【发布时间】:2022-01-01 17:34:19
【问题描述】:

我在集合中有具有结构的文档:

{key: {0: 2, 1: 5, 2: 100, 4: 15}}

我需要将 key: value 对添加到字典中。 value 可以是任何东西。没关系。但key必须是字典中不作为键使用的最小整数(从0开始)。

我可以用 python 做到这一点。

document = {key: {0: 2, 1: 5, 2: 100, 4: 15}}
new_key = 0  # key to insert in our dict
for i in range(max(document['key'].keys()) + 2):
    if i not in document['key'].keys():
        new_key = i

# update the document
document['key'][new_key] = value  # value may be anything

如何使用 MongoDB 做到这一点?有可能吗?

【问题讨论】:

    标签: mongodb dictionary mongodb-query


    【解决方案1】:

    这是一种可能性(需要Mongo 4.2 或更好):

    // { key: { 0: 2, 1: 5, 2: 100, 4: 15 } }
    db.collection.update(
      {},
      [
        { $set: {
          newkey: {
            $toString: {
              $min: {
                $setDifference: [
                  { $range: [0, 10] },
                  { $map: {
                    input: { $objectToArray: "$key" },
                    as: "x",
                    in: { $toInt: "$$x.k" }
                  }}
                ]
              }
            }
          }
        }},
        { $set: {
          key: {
            $arrayToObject: {
              $concatArrays: [
                { $objectToArray: "$key" },
                [{ k: "$newkey", v: 1000 }]
              ]
            }
          }
        }},
        { $unset: "newkey" }
    ])
    // { key: { 0: 2, 1: 5, 2: 100, 4: 15, 3: 1000 } }
    

    请注意,我们正在使用带有聚合管道(由 update({}, [...]) 中的方括号表示)的 update,该管道从 Mongo 4.2 开始可用,没有它我们无法根据自己的文档更新文档内容。

    第一个$set 阶段用于创建一个临时值,该值是添加新值的新键(在我们的例子中为3):

    • 首先将key 对象转换为{ k: "key", v: "value" } 对象数组,以便轻松访问键(请参阅$objectToArray):

      { $objectToArray: "$key" }
      // { key: [{ k: "0", v: 2 }, { k: "1", v: 5 }, { k: "2", v: 100 }, { k: "4", v: 15 }] }
      
    • 然后我们将k 键转换为整数数组(参见$map$toInt):

      { $map: { input: { ... }, as: "x", in: { $toInt: "$$x.k" } } }
      // [ 0, 1, 2, 4 ]
      
    • 然后我们与 0 到任何值(此处为 10)之间的范围相交(参见 $setDifference$range):

      $setDifference: [{ $range: [0, 10] }, {...}]
      // [ 3, 5, 6, 7, 8, 9 ]
      
      • 但如果您希望根据数组的最大键获得一个上限,也可以):只需将 10 替换为:

        { $max: { $map: { input: { $objectToArray: "$key" }, as: "x", in: { $toInt: "$$x.k" } } } }
        // 4
        
    • 我们可以从中提取最小值:

      $min: { ... }
      // 3
      
    • 我们转换成字符串:

      $toString: { ... }
      // "3"
      
    • 这样文档的中间版本就变成了:

      { key: { 0: 2, 1: 5, 2: 100, 4: 15 }, newkey: "3" }
      

    第二个$set 阶段将key 对象替换为现有的key 对象,并附加了新的键值:

    • 首先,将key 对象转换为{ k: "key", v: "value" } 对象数组:

      { $objectToArray: "$key" }
      // { key: [{ k: "0", v: 2 }, { k: "1", v: 5 }, { k: "2", v: 100 }, { k: "4", v: 15 }] }
      
    • 为了通过$concatArrays 操作附加新的键/值:

      $concatArrays: [{...}, [{ k: "$newkey", v: 1000 }]]
      // { key: [{ k: "0", v: 2 }, { k: "1", v: 5 }, { k: "2", v: 100 }, { k: "4", v: 15 }, { k: "3", v: 1000 }] }
      
    • 我们最终可以转换回对象的数组(参见$arrayToObject):

      $arrayToObject: { ... }
      // { 0: 2, 1: 5, 2: 100, 4: 15, 3: 1000 }
      

    最后一个阶段,$unset 阶段,用于删除中间变量 newkey

    请注意,可以通过将"$newkey" 替换为第一个$set 的内容,将第一个$set 阶段插入第二个阶段,但我认为这样可读性会降低。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-24
      • 2010-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多