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"
}
}
]
}
}
}
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" ]
}
}
]
}
}
}
}
}])
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"
]
]
}
}
}
}
}
])