【问题标题】:How to use $addFields to create an array in MongoDB?如何使用 $addFields 在 MongoDB 中创建数组?
【发布时间】:2020-09-06 04:44:39
【问题描述】:

作为一个更大问题的一部分,我正在尝试使用 $addFields 创建一个值数组,当它不匹配时,它会产生默认值“none”,但当它匹配时,它会返回 null。这是数据示例和我当前的 $addFields 聚合阶段:

{ 
'_id' : ObjectId(''),
'Region' : 'Northern',
'Orgtype1' : 'A1',
'Orgtype2' : null,
'Orgtype3' : null
}
{ 
'_id' : ObjectId(''),
'Region' : 'Northern',
'Orgtype1' : 'A4',
'Orgtype2' : 'B2',
'Orgtype3' : null
}
{ 
'_id' : ObjectId(''),
'Region' : 'Northern',
'Orgtype1' : 'B5',
'Orgtype2' : 'C1',
'Orgtype3' : 'D0'
}




{ '$addFields :{
    'Affinity': {
         '$switch' : {
            'branches': [
                { case: { $regexMatch : { 'input' : '$Orgtype1', 'regex': /^A/ } }, then: {'$concatArrays' :[ '$Affinity',['A'] ] } },
                { case: { $regexMatch : { 'input' : '$Orgtype2', 'regex': /^A/ } }, then: {'$concatArrays' :[ '$Affinity',['A'] ] } },
                { case: { $regexMatch : { 'input' : '$Orgtype3', 'regex': /^A/ } }, then: {'$concatArrays' :[ '$Affinity',['A'] ] } }
                ],
                'default':'none'
        }
    },
}}

当我运行该聚合阶段并对 Affinity 进行 $project 时,它会在任何不匹配的对象上返回“Affinity: none”,但在匹配的对象上返回“Affinity: null”。如何让它创建“关联”作为数组而不是字段/值对?

预期结果:

{ 
'_id' : ObjectId(''),
'Region' : 'Northern',
'Orgtype1' : 'A1',
'Orgtype2' : null,
'Orgtype3' : null,
'Affinity' : [ 'A' ]
}
{ 
'_id' : ObjectId(''),
'Region' : 'Northern',
'Orgtype1' : 'A4',
'Orgtype2' : 'B2',
'Orgtype3' : null,
'Affinity' : [ 'A', 'B' ]
}
{ 
'_id' : ObjectId(''),
'Region' : 'Northern',
'Orgtype1' : 'B5',
'Orgtype2' : 'C1',
'Orgtype3' : 'D0',
'Affinity' : [ 'B', 'C', 'D' ]
}

【问题讨论】:

  • 您能否根据这些文件添加您的预期结果。如果我没记错请看this
  • 最终需要匹配 20 个 Orgtype 代码,每个组织的数组最多有 3 个可能。我不是 100% 确定,但我认为您提供的解决方案只会用单个值覆盖数组
  • 当您搜索 A 时,您能否解释一下如何在第二个文档中返回 'Affinity' : [ 'A', 'B' ]
  • 给出的示例是结构的基础知识,addFields 必须遍历每个代码值,从 A 开始,然后移动到后续的值。最终,填充了三个类型字段的组织将拥有一个 [v1, v2, v3] 数组,具有 2 的组织将有两个数组元素,1 代表 1,而没有填充的组织则为空数组。当我尝试你的方法时,一个组织有两个代码,专门匹配它们,数组只返回一个值
  • 我知道提供的示例对您没有帮助,当然会返回一个值,我没有得到您的期望,有人会提供帮助。

标签: arrays mongodb


【解决方案1】:

我的建议是这个:

db.collection.aggregate([
  {
    "$addFields": {
      "Affinity": {
        $reduce: {
          input: [ "$Orgtype1", "$Orgtype2", "$Orgtype3" ],
          initialValue: [],
          in: { $concatArrays: [ "$$value", [ { $substrCP: [ "$$this", 0, 1 ] } ] ] } }
      }
    }
  },
  {
    $set: {
      Affinity: {
        $filter: {
          input: "$Affinity",
          cond: { $ne: [ "$$this", "" ] }
        }
      }
    }
  }
])

但是,我不确定它是否满足您的要求。它适用于示例文档。

Mongo Playground

或先应用过滤器,然后减少:

db.collection.aggregate([
  {
    $addFields: {
      Affinity: {
        $filter: {
          input: [ "$Orgtype1", "$Orgtype2", "$Orgtype3" ],
          cond: { $ne: [ "$$this", null ] }
        }
      }
    }
  },
  {
    $set: {
      "Affinity": {
        $reduce: {
          input: "$Affinity",
          initialValue: [],
          in: { $concatArrays: [ "$$value", [ { $substrCP: [ "$$this", 0, 1 ] } ] ] }
        }
      }
    }
  }
])

【讨论】:

  • 感谢您的回答。我承认这个特殊的解决方案超出了我的想象,因为我目前还没有使用 map reduce 的经验。它看起来比我制定的解决方案更优雅,所以我必须花一些时间来理解它。再次感谢
【解决方案2】:

为了遍历字段以创建最终数组,我必须首先将字段定义为数组,然后连接每个集合的 switch 分支的结果,从而产生预期的结果。

这是新聚合阶段的精简版:

{ "$addFields" : { "Affinity" : [] } }, 
{ "$addFields" : { 
 "Affinity": {
  "$concatArrays": [ 
   "$Affinity", {
     "$switch" : {
      "branches": [
       { case: { $regexMatch : { "input" : "$Orgtype1", "regex": /^A/ } }, then: ["A"] },
       { case: { $regexMatch : { "input" : "$Orgtype1", "regex": /^B/ } }, then: ["B"] },
       { case: { $regexMatch : { "input" : "$Orgtype1", "regex": /^C/ } }, then: ["C"] }
       ],
      default : []
     }}]}}}
{ "$addFields" : { 
 "Affinity": {
  "$concatArrays": [ 
   "$Affinity", {
     "$switch" : {
      "branches": [
       { case: { $regexMatch : { "input" : "$Orgtype2", "regex": /^A/ } }, then: ["A"] },
       { case: { $regexMatch : { "input" : "$Orgtype2", "regex": /^B/ } }, then: ["B"] },
       { case: { $regexMatch : { "input" : "$Orgtype2", "regex": /^C/ } }, then: ["C"] }
       ],
      default : []
     }}]}}}
{ "$addFields" : { 
 "Affinity": {
  "$concatArrays": [ 
   "$Affinity", {
     "$switch" : {
      "branches": [
       { case: { $regexMatch : { "input" : "$Orgtype3", "regex": /^A/ } }, then: ["A"] },
       { case: { $regexMatch : { "input" : "$Orgtype3", "regex": /^B/ } }, then: ["B"] },
       { case: { $regexMatch : { "input" : "$Orgtype3", "regex": /^C/ } }, then: ["C"] }
       ],
      default : []
     }}]}}}

这会正确创建 Affinity 数组,然后附加在每个 Orgtype 列中找到的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-04-07
    • 2019-04-15
    • 2018-04-28
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    • 1970-01-01
    相关资源
    最近更新 更多