0

I have problem statement, in which i need all the field names at child level of "config.first.second" where include field is true at least once. Here is my mongo collection objects.

   [ {
        "_id" : ObjectId("560e97f4a78eb445cd2d75e5"),
        "config" : {
            "first" : {
                "second" : {
                    "field1" : {
                       "include":"true"
                    },
                    "field3" : {
                      "include":"true"
                    },
                    "field9" : {
                        "include":"false"
                    },
                    "field6" : {
                        "include":"false"
                    }
                }
            }
        },
        "date_created" : "Fri Oct 02 14:43:00 UTC 2015",
        "last_updated" : "Mon Apr 11 15:26:37 UTC 2016",
        "id" : ObjectId("560e97f4a78eb445cd2d75e5")
    },
    {
        "_id" : ObjectId("56154465a78e41c04692af20"),
        "config" : {
            "first" : {
                "second" : {
                    "field1" : {
                        "include":"true"
                    },
                    "field3" : {
                        "include":"false"
                    },
                    "field7" : {
                    "include":"true"
                    }
                }
            }
        },
        "date_created" : "Wed Oct 07 16:12:21 UTC 2015",
        "last_updated" : "Mon Apr 11 15:18:58 UTC 2016",
        "id" : ObjectId("56154465a78e41c04692af20")
    }
]

Using above mongo collection . Query must return result

["field1","field3","field7"]
Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
Haider Ali
  • 342
  • 2
  • 11
  • It's a horrible structure with absolutely no utility to query. You need to recurse through JavaScript to do anything. The structure needs to change, as this simply is not what you use a database for. Use a XML document store if you think this is the structure you want. – Neil Lunn Jul 03 '17 at 10:18
  • May be it is but can't be changed. Is it like i can only loop. Not like a good solution. Tried projecting like this db.getCollection('my_collection').aggregate([ { $project : {result: "$config.first.second" } } ]) but not helping – Haider Ali Jul 03 '17 at 10:35
  • You cannot use aggregate or any standard query terms. mapReduce only. – Neil Lunn Jul 03 '17 at 10:36
  • https://stackoverflow.com/questions/2298870/mongodb-get-names-of-all-keys-in-collection . Tried this but not working for me. Maybe I am missing something – Haider Ali Jul 03 '17 at 10:43

1 Answers1

2

You can run with mapReduce:

db.collection.mapReduce(
  function() {
    Object.keys(this.config.first.second)
      .filter( k => this.config.first.second[k].include === "true" )
      .forEach(k => emit(k,1) );
  },
  function() { },
  { 
    "out": { "inline": 1 },

  }
)['results'].map( d => d._id )

If you have MongoDB 3.4 then you can use .aggregate():

db.collection.aggregate([
  { "$project": {
    "field": {
      "$filter": {
        "input": { "$objectToArray": "$config.first.second" },
        "as": "f",
        "cond": { "$eq": [ "$$f.v.include", "true" ] }
      }
    }
  }},
  { "$unwind": "$field" },
  { "$group": { "_id": "$field.k" } }
]).toArray().map(d => d._id)

Returns:

[
    "field1",
    "field3",
    "field7"
]
Neil Lunn
  • 148,042
  • 36
  • 346
  • 317