atline
atline

Reputation: 31574

How to combine mongodb original output of query with some new fields?

Collection:

[
  {
    "name": "device1",
    "type": "a",
    "para": {
      "number": 3
    }
  },
  {
    "name": "device2",
    "type": "b",
    "additional": "c",
    "para": {
      "number": 1
    }
  }
]

My query:

db.collection.aggregate([
  {
    "$addFields": {
      "arrayofkeyvalue": {
        "$objectToArray": "$$ROOT"
      }
    }
  },
  {
    "$unwind": "$arrayofkeyvalue"
  },
  {
    "$group": {
      "_id": null,
      "allkeys": {
        "$addToSet": "$arrayofkeyvalue.k"
      }
    }
  }
])

The output currently:

[
  {
    "_id": null,
    "allkeys": [
      "additional",
      "_id",
      "para",
      "type",
      "name"
    ]
  }
]

Detail see Playground

What I want to do is add a new column which includes all of top key of the mongodb query output, exclude "para". And then combine it with the old collection to form a new json.

Is it possible?

The expected result:

{
    "column": [{"prop": "name"}, {"prop": "type"}, {"prop": "additional"}],
    "columnData": [
        {
            "name": "device1",
            "type": "a",
            "para": {
                "number": 3
            }
        },
        {
            "name": "device2",
            "type": "b",
            "additional": "c",
            "para": {
                "number": 1
            }
        }
    ]
}

Upvotes: 1

Views: 67

Answers (1)

Tom Slabbaert
Tom Slabbaert

Reputation: 22276

You have the right general idea in mind, here's how I would do it by utilizing operators like $filter, $map and $reduce to manipulate the objects structure.

I separated the aggregation into 3 parts for readability but you can just merge stage 2 and 3 if you wish.

db.collection.aggregate([
  {
    "$group": {
      "_id": null,
      columnData: {
        $push: "$$ROOT"
      },
      "keys": {
        "$push": {
          $map: {
            input: {
              "$objectToArray": "$$ROOT"
            },
            as: "field",
            in: "$$field.k"
          }
        }
      }
    }
  },
  {
    "$addFields": {
      unionedKeys: {
        $filter: {
          input: {
            $reduce: {
              input: "$keys",
              initialValue: [],
              in: {
                "$setUnion": [
                  "$$this",
                  "$$value"
                ]
              }
            }
          },
          as: "item",
          cond: {
            $not: {
              "$setIsSubset": [
                [
                  "$$item"
                ],
                [
                  "_id",
                  "para"
                ]
              ]
            }
          }
        }
      }
    }
  },
  {
    $project: {
      _id: 0,
      columnData: 1,
      column: {
        $map: {
          input: "$unionedKeys",
          as: "key",
          in: {
            prop: "$$key"
          }
        }
      }
    }
  }
])

Mongo Playground

Upvotes: 1

Related Questions