Using $unwind over object properties

Is it possible to use $unwind over the properties of an object when making a query with agregation in MongoDB v3?

I need to extract the controls that meet a certain condition on each object from the object array of each areas key. The question is that the keys in areas can vary. You can have two keys as in the example, but in other cases you can have up to 3 and 4 four keys.

{
   id: 12,
   name: "adsdf",
   areas: {
      clave1: [
         {
            "controles": ["valor1","valor2","valor3"]          
         },
         {
            "controles": ["valor4","valor5","valor6"]          
         }
      ],
      clave2: [
         {
            "controles": ["valor7","valor8","valor9"]          
         },
         {
            "controles": ["valor10","valor11","valor12"]          
         }
      ]
   }
}

A result would be something like this for example:

{
   id: 12,
   name: "adsdf",
   areas: {
      clave1: [
         {
            "controles": ["valor1","valor3"]          
         },
         {
            "controles": ["valor5"]          
         }
      ],
      clave2: [
         {
            "controles": ["valor9"]          
         },
         {
            "controles": ["valor12"]
         }
      ]
   }
}
 4
Author: Carlos Muñoz, 2015-12-16

2 answers

MongoDB is a system in which there is no predefined schema for objects in a collection. It is very likely and, in addition, highly recommended that the documents of a particular collection have a similar structure. If it is the case that there are documents in the same collection with different structure we must manage it in the logic of the application.

In your particular case, the "areas" field differs from document to document, as it contains different fields: key 1, KEY2 for one document; key 1, Key 2, key 3 for another document; etc.

The nature of the field itself leads to thinking that it should be of type array, since it contains a random number of elements and that, in addition, are of the same type.

On the other hand, and as César Bustíos has already commented, The command $unwind of aggregation framework only works on arrays.

That said, an approach to solving your problem may be to perform a search for the names of the fields containing the "areas" subdocument using mapReduce and from the results, look for the value of such fields by programming. The following example can help you get the names of those fields:

mr = db.mapreduce.mapReduce(
    function() { for (var key in this.areas) {emit(key, null)}},
    function(key, stuff) {return null;},
    { out:"my_collection" + "_keys" }
)

db[mr.result].distinct("_id")
 2
Author: hecnabae, 2015-12-16 21:30:54

In the documentation of $unwind it is very clear what you can achieve. Using that same example, if you have a collection inventario:

{ "_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] }

Using $unwind you can get a document for each element of the array sizes:

db.inventario.aggregate( [ { $unwind : "$sizes" } ] )

Will throw you as a result:

{ "_id" : 1, "item" : "ABC1", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "L" }

Is like doing an "explode" to the array sizes.

 2
Author: César, 2015-12-16 15:16:47