Home > OS >  How to fetch field Names inside an Array of Collection in mongoDB?
How to fetch field Names inside an Array of Collection in mongoDB?

Time:11-27

I am trying to fetch the field Names present in the mongo DB collection, so far I have built till here :

db.getCollection('appd_application_master').aggregate([
{"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
  {"$unwind":"$arrayofkeyvalue"},
  {"$group":{"_id":null,"allkeys":{"$addToSet":"$arrayofkeyvalue.k"}}},
  {"$unwind":"$allkeys"}
])

But the problem is if the collection holds any array then the fields inside it I'm unable to access, can some please help or guide in the right direction?TIA

Here is a sample record of the collection

{
  "_class": "com.json.SvnCommitMst",
  "_id": "38735",
  "author": "10662365",
  "commitDate": ISODate( "2021-09-30T08:28:01.159Z"),
  "isLatest": false,
  "mapSvnFilesMst": [
    {
      "_id": ObjectId( "618df1b32109446cb6ef58d6"),
      "commitAction": "MODIFY"
    }
  ],
  "message": "Rohit:\n\nUser Repo tool validation changes",
  "projectToolId": 92
}

The response I'm getting with the current query:

{
    "_id" : null,
    "allkeys" : [ 
        "isLatest", 
        "author", 
        "_id", 
        "message", 
        "projectToolId", 
        "_class", 
        "mapSvnFilesMst", 
        "commitDate"
    ]
}

CodePudding user response:

Based on the assumption that you know the names of your array(s) you can use two $project stages to get all keys combined. In both of them you can refer to more than one variable.

The $let operator becomes handy to get rid of additional stages:

{
    $addFields: {
        mapSvnFilesMst: {
            $reduce: {
                input: "$mapSvnFilesMst",
                initialValue: [],
                in: {
                    $setUnion: [
                        "$$value",
                        {
                            $let: {
                                vars: {
                                    kv: { $objectToArray: "$$this" }
                                },
                                in: "$$kv.k"
                            }
                        }
                    ]
                }
            }
        }
    }
},
{
    $project: {
        allKeys: {
            $setUnion: [
                "$mapSvnFilesMst",
                {
                    $let: {
                        vars: { kv: { $objectToArray: "$$ROOT" } },
                        in: "$$kv.k"
                    }
                }
            ]
        }
    }
}

Mongo Playground

You can also try below query to scan your documents without specifying the name of any array - works only for one level of arrays (without recursion):

db.collection.aggregate([{
    $project: {
        allKeys: {
            $reduce: {
                input: { $objectToArray: "$$ROOT" },
                initialValue: [],
                in: {
                    $setUnion: [
                        "$$value",
                        {
                            $cond: {
                                if: { $eq: [ { $type: "$$this.v" }, "array" ] },
                                then: {
                                    $setUnion: [
                                        ["$$this.k"],
                                        {
                                            $reduce: {
                                                input: "$$this.v",
                                                initialValue: [],
                                                in: {
                                                    $setUnion: [
                                                        "$$value",
                                                        {
                                                            $let: {
                                                                vars: { kv: { $objectToArray: "$$this" } },
                                                                in: "$$kv.k"
                                                            }
                                                        }
                                                    ]
                                                }
                                            }
                                        }
                                    ]
                                },
                                else: [ "$$this.k" ]
                            }
                        }
                    ]
                }
            }
        }
    }
}])

Mongo Playground (2)

CodePudding user response:

There's a simplier solution as long as you need only the first level of keys :

db.collection.aggregate([
  {
    $project: {
      allKeys: {
        "$reduce": {
          "input": {
            "$objectToArray": "$$ROOT"
          },
          "initialValue": [],
          "in": {
            "$concatArrays": [
              "$$value",
              [
                "$$this.k"
              ]
            ]
          }
        }
      }
    }
  }
])

You can try it here

  • Related