1

Followup Question

Thanks @4J41 for your spot on resolution. Along the same lines, I'd also like to validate one other thing.

I have a mongo document that contains an array of Strings, and I need to convert this particular array of strings into an array of object containing a key-value pair. Below is my curent appraoch to it.

Mongo Record: Same mongo record in my initial question below.

Current Query:

templateAttributes.find({platform:"V1"}).map(function(c){
  //instantiate a new array
  var optionsArray = [];
for (var i=0;i< c['available']['Community']['attributes']['type']['values'].length; i++){
    optionsArray[i] = {};              // creates a new object
    optionsArray[i].label = c['available']['Community']['attributes']['type']['values'][i];
    optionsArray[i].value = c['available']['Community']['attributes']['type']['values'][i];
    }
    return optionsArray;
})[0];

Result:

[{label:"well-known", value:"well-known"},
{label:"simple", value:"simple"},
{label:"complex", value:"complex"}]

Is my approach efficient enough, or is there a way to optimize the above query to get the same desired result?


Initial Question

I have a mongo document like below:

{
    "_id" : ObjectId("57e3720836e36f63695a2ef2"),
    "platform" : "A1",
    "available" : {
        "Community" : {
            "attributes" : {
                "type" : {
                    "values" : [
                        "well-known",
                        "simple",
                        "complex"
                    ],
                    "defaultValue" : "well-known"
                },
[......]


}

I'm trying to query the DB and retrieve only the value of defaultValue field.

I tried:

db.templateAttributes.find(
    { platform: "A1" },   
    { "available.Community.attributes.type.defaultValue": 1 }
)

as well as

db.templateAttributes.findOne(
    { platform: "A1" },    
    { "available.Community.attributes.type.defaultValue": 1 }
)

But they both seem to retrieve the entire object hirarchy like below:

{
    "_id" : ObjectId("57e3720836e36f63695a2ef2"),
    "available" : {
        "Community" : {
            "attributes" : {
                "type" : {
                    "defaultValue" : "well-known"
                }
            }
        }
    }
}

The only way I could get it to work was with find and map function, but it seems to be convoluted a bit.

Does anyone have a simpler way to get this result?

db.templateAttributes.find(
    { platform: "A1" },    
    { "available.Community.attributes.type.defaultValue": 1 }
).map(function(c){
    return c['available']['Community']['attributes']['type']['defaultValue']
})[0]

Output

well-known
blueren
  • 2,730
  • 4
  • 30
  • 47

1 Answers1

1

You could try the following.

Using find:

db.templateAttributes.find({ platform: "A1" }, { "available.Community.attributes.type.defaultValue": 1 }).toArray()[0]['available']['Community']['attributes']['type']['defaultValue']

Using findOne:

db.templateAttributes.findOne({ platform: "A1" }, { "available.Community.attributes.type.defaultValue": 1 })['available']['Community']['attributes']['type']['defaultValue']

Using aggregation:

db.templateAttributes.aggregate([
                                  {"$match":{platform:"A1"}}, 
                                  {"$project": {_id:0, default:"$available.Community.attributes.type.defaultValue"}}
                             ]).toArray()[0].default

Output:

well-known

Edit: Answering the updated question: Please use aggregation here.

db.templateAttributes.aggregate([
                                    {"$match":{platform:"A1"}}, {"$unwind": "$available.Community.attributes.type.values"}, 
                                    {$group: {"_id": null, "val":{"$push":{label:"$available.Community.attributes.type.values", 
                                                                            value:"$available.Community.attributes.type.values"}}}}
                                ]).toArray()[0].val

Output:

[
    {
            "label" : "well-known",
            "value" : "well-known"
    },
    {
            "label" : "simple",
            "value" : "simple"
    },
    {
            "label" : "complex",
            "value" : "complex"
    }
]
4J41
  • 5,005
  • 1
  • 29
  • 41
  • I'm still quite new to mongo. I don't really need to change any structure of the doc. I'm only interested in a query that gets me only the value of that field. I already have the map approach working for me, but I just wated to know if there is a better way of doing it – blueren Sep 22 '16 at 07:34
  • @blueren: Updated my answer. – 4J41 Sep 22 '16 at 12:36
  • 1
    Amazing! Thanks. This was what I was looking for. Bu I'd like to have a bit of understanding as to how this works. Find returns a cursor and you're converting it to an arary and picking the 0th element? Same goes for findOne? – blueren Sep 23 '16 at 04:53
  • @blueren: I have the code for findOne in my answer too. With findOne, you will receive a single document (not a cursor). So no need to convert to array and access the 0th element. You can access the fields directly. – 4J41 Sep 23 '16 at 04:58
  • 1
    Thanks @4J41, I have a follow up question. I've updated the main question. – blueren Sep 23 '16 at 05:29
  • @blueren: Could you please post the follow up question as a new question to attract more supporters? – 4J41 Sep 23 '16 at 05:56
  • Done. Here's the [link](http://stackoverflow.com/questions/39653872/converting-mongo-array-to-object-with-key-value-pair) – blueren Sep 23 '16 at 06:22