2

When querying mongodb, is it possible to process ("project") the result so as to perform array concatenation? I actually have 2 different scenarios:

(1) Arrays from different fields:, e.g:

Given:
{companyName:'microsoft', managers:['ariel', 'bella'], employees:['charlie', 'don']}
{companyName:'oracle',   managers:['elena', 'frank'], employees:['george', 'hugh']}

I'd like my query to return each company with its 'managers' and 'employees' concatenated:
{companyName:'microsoft', allPersonnel:['ariel', 'bella','charlie', 'don']}
{companyName:'oracle',   allPersonnel:['elena', 'frank','george', 'hugh']}

(2) Nested arrays:, e.g.:

Given the following docs, where employees are separated into nested arrays (never mind why, it's a long story):
{companyName:'microsoft', personnel:[ ['ariel', 'bella'], ['charlie', 'don']}
{companyName:'oracle',   personnel:[ ['elena', 'frank'], ['george', 'hugh']}

I'd like my query to return each company with a flattened 'personal' array:
{companyName:'microsoft', allPersonnel:['ariel', 'bella','charlie', 'don']}
{companyName:'oracle',   allPersonnel:['elena', 'frank','george', 'hugh']}

I'd appreciate any ideas, using either 'find' or 'aggregate' Thanks a lot :)

1 Answer 1

3

Of Course in Modern MongoDB releases we can simply use $concatArrays here:

db.collection.aggregate([
  { "$project": {
    "companyNanme": 1,
    "allPersonnel": { "$concatArrays": [ "$managers", "$employees" ] }
  }}
])

Or for the second form with nested arrays, using $reduce in combination:

db.collection.aggregate([
  { "$project": {
    "companyName": 1,
    "allEmployees": {
      "$reduce": {
        "input": "$personnel",
        "initialValue": [],
        "in": { "$concatArrays": [ "$$value", "$$this" ] }
      }
    }
  }}
])

There is the $setUnion operator available to the aggregation framework. The constraint here is that these are "sets" and all the members are actually "unique" as a "set" requires:

db.collection.aggregate([
    { "$project": {
        "companyname": 1,
        "allPersonnel": { "$setUnion": [ "$managers", "$employees" ] }
    }}
])

So that is cool, as long as all are "unique" and you are in singular arrays.

In the alternate case you can always process with $unwind and $group. The personnel nested array is a simple double unwind

db.collection.aggregate([
   { "$unwind": "$personnel" },
   { "$unwind": "$personnel" },
   { "$group": {
       "_id": "$_id",
       "companyName": { "$first": "$companyName" },
       "allPersonnel": { "$push": { "$personnel" } }
   }}
])

Or the same thing as the first one for versions earlier than MongoDB 2.6 where the "set operators" did not exist:

db.collection.aggregate([
    { "$project": {
        "type": { "$const": [ "M", "E" ] },
        "companyName": 1,
        "managers": 1,
        "employees": 1
    }},
    { "$unwind": "$type" },
    { "$unwind": "$managers" },
    { "$unwind": "$employees" },
    { "$group": {
        "_id": "$_id",
       "companyName": { "$first": "$companyName" },
       "allPersonnel": {
           "$addToSet": {
               "$cond": [
                   { "$eq": [ "$type", "M" ] },
                   "$managers",
                   "$employees"
               ]
           }
       }
    }}
])
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.