130

I'm getting returned a JSON value from MongoDB after I run my query. The problem is I do not want to return all the JSON associated with my return, I tried searching the docs and didn't find a proper way to do this. I was wondering what if it is at possible, and if so what is the proper way of doing such. Example: In the DB

{
    user: "RMS",
    OS: "GNU/HURD",
    bearded: "yes",
    philosophy: {
        software: "FOSS",
        cryptology: "Necessary"
    },
    email: {
        responds: "Yes",
        address: "rms@gnu.org"
    },
    facebook: {}
}

{
    user: "zuckerburg",
    os: "OSX",
    bearded: "no",
    philosophy: {
        software: "OSS",
        cryptology: "Optional"
    },
    email: {},
    facebook: {
        responds: "Sometimes",
        address: "https://www.facebook.com/zuck?fref=ts"
    }
} 

What would be the proper way of returning a field if it exists for a user, but if it doesn't return another field. For the example above I would want to return the [email][address] field for RMS and the [facebook][address] field for Zuckerburg. This is what I have tried to find if a field is null, but it doesn't appear to be working.

 .populate('user' , `email.address`)
  .exec(function (err, subscription){ 
    var key;
    var f;
    for(key in subscription){
      if(subscription[key].facebook != null  ){
          console.log("user has fb");
      }
    }
  }
Alexis Tyler
  • 1,394
  • 6
  • 30
  • 48
Sleep Deprived Bulbasaur
  • 2,368
  • 4
  • 21
  • 33

14 Answers14

122

I'm not completely clear on what you mean by "returning a field", but you can use a lean() query so that you can freely modify the output, then populate both fields and post-process the result to only keep the field you want:

.lean().populate('user', 'email.address facebook.address')
  .exec(function (err, subscription){ 
    if (subscription.user.email.address) {
        delete subscription.user.facebook;
    } else {
        delete subscription.user.email;
    }
  });
JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
  • 1
    this not working for me, anyone knows if this has changed with an Mongoose update? – Ninja Coding Nov 10 '17 at 16:59
  • 1
    This is not working for me either, I tried `.populate('model', 'field')`, `.populate('model', { field: 1})`, `.populate('model', [field])` with and without `lean()` and with and without `selectPopulatedPaths: false` on the model but I always got the full populated object in the response. The documentation says your answer is supposed to be the right one but I can't make it work. Is somebody having the same issue ? – mel-mouk Nov 19 '19 at 13:55
81

If you only want a few specific fields to be returned for the populated documents, you can accomplish this by passing the field name syntax as the second argument to the populate method.

Model
.findOne({ _id: 'bogus' })
.populate('the_field_to_populate', 'name') // only return the Persons name
...

See Mongoose populate field selection

dontmentionthebackup
  • 2,775
  • 1
  • 21
  • 18
  • 13
    Works fine. You can also returned more fields, only you must pass more fields. --> populate('the_field_to_populate', 'name lastname') – saeta Dec 16 '15 at 06:27
  • What if you had more than one model to populate and wanted fields for those? Like populate('users posts','name')? Would you get names for both? – MoDrags Mar 21 '17 at 16:40
  • Something like this: Model.findOne({_id: 'foo'}).populate({ path: 'parent-model', populate: { path: 'someProperty', populate: { path: 'somePropertyBelow' } } }) – dontmentionthebackup Mar 28 '17 at 13:05
57

Try to do this:

applicantListToExport: function (query, callback) {
  this
   .find(query).select({'advtId': 0})
   .populate({
      path: 'influId',
      model: 'influencer',
      select: { '_id': 1,'user':1},
      populate: {
        path: 'userid',
        model: 'User'
      }
   })
 .populate('campaignId',{'campaignTitle':1})
 .exec(callback);
}
Naveen Kumar
  • 987
  • 11
  • 11
29

Try to do this:

User.find(options, '_id user email facebook').populate('facebook', '_id pos').exec(function (err, users) {
scuencag
  • 664
  • 4
  • 11
28

Now what you can do is :

  .populate('friends', { username: 1, age: 1})
Scaraux
  • 3,841
  • 4
  • 40
  • 80
14

In the following query i retrieved articles which match the condition show=true the retrieved data title and createdAt also retrieve the category of article only the title of category and it's id.

let articles = await articleModel
        .find({ show: true }, { title: 1, createdAt: 1 })
        .populate("category", { title: 1, _id: 1 });
Ahmed Mahmoud
  • 1,724
  • 1
  • 17
  • 21
8

for a single level populate you can use -> populate('user','name email age')

for nested population

populate({
    path:'posts',
    populate({
         path:'user'
         select:'name email age'
    })
})
phsource
  • 2,326
  • 21
  • 32
Sumit Garg
  • 91
  • 1
  • 1
4

you to try :

Post.find({_id: {$nin: [info._id]}, tags: {$in: info.tags}}).sort({_id:-1})
.populate('uid','nm')
.populate('tags','nm')
.limit(20).exec();
Tran Hoang Hiep
  • 544
  • 5
  • 12
4

I was stuck on this issue. I wanted to populator and user field linked to the Blog Post. Using populate only returned everything including the password. By specifying fields as an array it works fine.

//code emitted for brevity

await Blog.findById(ID).populate("author", ["firstName", "lastName", 
"profilePicture", "_id"])

//

This is the result of the response

Response

2

Just to complement the answers above, if you want to include everything but only exclude certain attributes, you can do the following:

.populate('users', {password: 0, preferences: 0})
Prashant Ghimire
  • 4,890
  • 3
  • 35
  • 46
0

you can try using below,

 Model
    .find()
    .populate({path: 'foreign_field', ['_id', 'name']}) // only return the Id and Persons name
    ...
Naresh Ramoliya
  • 770
  • 2
  • 8
  • 25
0

Hi for me it worked for me i populated user field using the populate code : --->

async function displayMessage(req,res,next){
    try{
        let data= await Msg.find().populate("user","userName userProfileImg","User")
               if(data===null) throw "Data couldn ot be loaded server error"
        else {
            res.status(200).json(data)
        }
    }   catch(err){
            next(err)
    }
}

i am directly getting the result . Here the fields userName , userProfile image are the ones that ive required selectively and the syntax for populate is :-->

 .populate("user field to populate","fields to display with spaces between each of them " , "modelName ")

every parameter should be in inverted comma's.

Below is the output i recieve.One more thing you don't have to worry about the populating sub-document id you will automatically get them.

[
    {
        "_id": "5e8bff324beaaa04701f3bb9",
        "text": "testing message route",
        "user": {
            "_id": "5e8bf062d3c310054cf9f293",
            "userName": "boss",
            "userProfileImg": "img"
        },
        "__v": 0
    },
    {
        "_id": "5e8bff8dd4368a2858e8f771",
        "text": "testing message route second",
        "user": {
            "_id": "5e8bf062d3c310054cf9f293",
            "userName": "boss",
            "userProfileImg": "img"
        },
        "__v": 0
    },
    {
        "_id": "5e8c0c08e9bdb8209829176a",
        "text": "testing message route second",
        "user": {
            "_id": "5e8bf062d3c310054cf9f293",
            "userName": "boss",
            "userProfileImg": "img"
        },
        "__v": 0
    },
    {
        "_id": "5e8c0e0bcb63b12ec875962a",
        "text": "testing message route fourth time",
        "user": {
            "_id": "5e8bf062d3c310054cf9f293",
            "userName": "boss",
            "userProfileImg": "img"
        },
        "__v": 0
    }
]
Amit Joshi
  • 15,448
  • 21
  • 77
  • 141
0

I tried with:

.populate('model', { field_1: 1, field_2: 1 }).exec()...
0

To populate multiple fields using findOne.

For example, this is your model

const productSchema = new mongoose.Schema(
    {
        user: {
            type: mongoose.Schema.Types.ObjectId,
            required: true,
            ref: "User",
        },
        store: {
            type: mongoose.Schema.Types.ObjectId,
            required: true,
            ref: "Store",
        },
        name: {
            type: String,
            required: true,
        },
    },
);

const Product = mongoose.model("Product", productSchema);

export default Product;

To populate store and user without using path, do this:

await Product.findOne({ name: "dancing shoe" }).populate("user store");

The next params will return a specific field in the populated models or just the _id where the field doesn't exist. In other words, the second params is used as select.

await Product.findOne({ name: "dancing shoe" }).populate("user store", "name");

This will populate user and store model with _id and name only

Emmanuella
  • 71
  • 1
  • 8