MongoDB Aggregation将字符串数组连接到单个字符串

时间:2016-07-14 14:57:31

标签: mongodb aggregation-framework

我们正在尝试将一个字符串数组'连接'到聚合内的单个字符串。

给出以下数据集:

收集1:

{
  id: 1234,
  field: 'test'
}

收集2:

{
  id: 1111,
  collection1_id: 1234,
  name: 'Max'
},
{
  id: 1112,
  collection1_id: 1234,
  name: 'Andy'
}

当前结果(查找后等):

{
  id: 1234,
  field: 'test',
  collection2: ['Max', 'Andy'] 
}

所需的结果:

{
  id: 1234,
  field: 'test',
  collection2: 'Max, Andy'
}

以某种方式可以将'collection2'加入单个字符串吗?我们尝试使用$concat,但它只接受字符串。

4 个答案:

答案 0 :(得分:8)

你走在正确的轨道上。

只需在$project阶段的$reduce上添加$concat

'collection2': {
    '$reduce': {
        'input': '$collection2',
        'initialValue': '',
        'in': {
            '$concat': [
                '$$value',
                {'$cond': [{'$eq': ['$$value', '']}, '', ', ']}, 
                '$$this']
        }
    }
}

注意:我们使用$cond来阻止串联中的前导,。 您也可以在$reduce之前使用$substrCP作为$cond的替代。

答案 1 :(得分:0)

要展平此数组,您需要将流程转移到客户端。

mongo将在新版本中提供一些新的展平选项,但是afaik将是算术版(avg,min,max ....)。

答案 2 :(得分:0)

Mongo 4.4开始,$group阶段有了一个新的聚合运算符$accumulator,允许在文件分组时进行自定义累积:

// { "collectionId" : 1234, "name" : "Max"  }
// { "collectionId" : 876,  "name" : "Rob"  }
// { "collectionId" : 1234, "name" : "Andy" }
db.collection.aggregate([
  { $group: {
    _id: "$collectionId",
    names: {
      $accumulator: {
        accumulateArgs: ["$name"],
        init: function() { return [] },
        accumulate: function(names, name) { return names.concat(name) },
        merge: function(names1, names2) { return names1.concat(names2) },
        finalize: function(names) { return names.join(",") },
        lang: "js"
      }
    }
  }}
])
// { "_id" : 876,  "names" : "Rob"      }
// { "_id" : 1234, "names" : "Max,Andy" }

累加器:

  • 累积在nameaccumulateArgs)字段上
  • 被初始化为空数组(init
  • 通过将新名称连接到已经看到的名称(accumulatemerge)来积累
  • 最后将所有名称作为字符串(finalize

答案 3 :(得分:0)

有时候使用JavaScript最简单:

db.getCollection('Collection1').aggregate([
{
   $lookup:
     {
       from: 'Collection2',
       localField: 'id',
       foreignField: 'collection1_id',
       as: 'col2'
     }
}]).map((e) => ({
  id: e.id,
  field: e.field,
 collection2: Array.isArray(e.col2) &&
   e.col2.reduce((arr, el) => {
     arr.push(el.name);
    return arr;
  }, []).join(', ')
}))