MongoDB Aggregation join array of strings to single string

前端 未结 4 862
长发绾君心
长发绾君心 2021-02-12 15:14

We\'re trying to \'join\' an array of strings to a single string within an aggregation.

Given is the following dataset:

Collection 1:

{
  id: 123         


        
相关标签:
4条回答
  • 2021-02-12 15:17

    Starting Mongo 4.4, the $group stage has a new aggregation operator $accumulator allowing custom accumulations of documents as they get grouped:

    // { "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" }
    

    The accumulator:

    • accumulates on the field name (accumulateArgs)
    • is initialised to an empty array (init)
    • accumulates by concatenating new names to already seen names (accumulate and merge)
    • and finally joins all names as a string (finalize)
    0 讨论(0)
  • 2021-02-12 15:22

    Sometimes it's easiest to use 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(', ')
    }))
    
    0 讨论(0)
  • 2021-02-12 15:23

    To flatten this array, you need to shift process to client.

    mongo will provide some new flattening options in new edition, but afaik it will be arithmetic ones (avg, min, max....).

    0 讨论(0)
  • 2021-02-12 15:26

    You were on the right track.

    Just add $reduce over $concat in your $project stage.

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

    Note: We use $cond to prevent a leading , in the concatenation. You could also use $substrCP before $reduce as an alternative to $cond.

    0 讨论(0)
提交回复
热议问题