10

I have a collection in mongodb where fields are nested under a language root:

{
    en: {
        title: "eng title",
        content: "eng content",
    },
    it: {
        title: "it title",
        content: "it content"
    }
    //common attributes for all languages
    images: {
        mainImage: "dataURL",
        thumbImage: "dataURL"
    }
}

I have a variable called 'currentLang'; I need to find a document by title selecting only the "currentLang" object and the common fields (images in this example); but for the "currentLang" object, I would like to have the output document not nested; for example, having currentLang = "en"

desired output:

{
    title: "eng title",
    content: "eng content",
    images: {
        mainImage: "dataURL",
        thumbImage: "dataURL"
    }
}

Is this possible?

Cereal Killer
  • 3,387
  • 10
  • 48
  • 80

2 Answers2

6

You need to aggregate as below:

  • Construct a find object to match only the records containing($exists) the language.
  • Construct a Projection object to project the fields.

Code:

var currentLang = "en";
var project = {};
project["title"] = "$"+currentLang+".title";
project["content"] = "$"+currentLang+".content";
project["images"] = 1;

var find = {};
find[currentLang] = {"$exists":true};

db.collection.aggregate([
{$match:find},
{$project:project}
])
BatScream
  • 19,260
  • 4
  • 52
  • 68
  • This is exactly the code that I'm using now; but the output document is still nested under "en"; I would like to have all fields in the root element, like the desired output written above – Cereal Killer Dec 05 '14 at 22:53
  • @CerealKiller Then you need to aggregate, to project a field with an alias. Please see the updated answer. – BatScream Dec 05 '14 at 22:59
  • Ok, this is correct; unfortunally, I'm using mongo inside Meteor.js, where aggregation seems to be not supported; sorry when I wrote the question I was not knowing that... – Cereal Killer Dec 05 '14 at 23:26
  • @CerealKiller No problem. - See if this helps http://stackoverflow.com/questions/18520567/average-aggregation-queries-in-meteor. Or You can post a new question asking for how this is to be done using meteor. – BatScream Dec 05 '14 at 23:28
  • Not super significant, but to follow standards -- Since the top 3 obj keys are static and known, you may want to use `project.title = ` instead of `project["title"] = ` (you can use the dot notation to create NEW fields inside the obj on-the-fly - it's ok if undefined as long as it's not nested undefined) – dylanh724 Jun 29 '18 at 07:53
4

I'm not sure how you're querying, so I'll assume you're going directly through the mongo client. Assuming you have defined a variable

>currentLang = "en";

You can run an aggregation operation and using the $project operator, restructure the presentation of the document.

Here's an example that I've tested:

> db.test.aggregate({$project: 
        {_id: 0, 
         title: "$" + currentLang + ".title", 
         content: "$" + currentLang + ".content", 
         images: 1
        }
    }).pretty();
{
    "images" : {
        "mainImage" : "dataURL",
        "thumbImage" : "dataURL"
    },
    "title" : "eng title",
    "content" : "eng content"
}

If you want to combine this with an actual query, you can just include it as a $match operator, something like:

> db.test.aggregate(
    {$match: 
        {"en.title": "eng title"}
    }, 
    {$project: 
        {_id: 0, 
         title: "$" + currentLang + ".title", 
         content: "$" + currentLang + ".content", 
         images: 1
        }
    }).pretty();
Verran
  • 3,942
  • 2
  • 14
  • 22