Возврат определенных полей с помощью .populate () из Mongoose

86

Мне возвращается значение JSON от MongoDB после выполнения запроса. Проблема в том, что я не хочу возвращать весь JSON, связанный с моим возвращением, я попытался выполнить поиск в документации и не нашел подходящего способа сделать это. Мне было интересно, что, если это возможно, и если да, то как правильно это сделать. Пример: в БД

{
    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"
    }
} 

Каким будет правильный способ возврата поля, если оно существует для пользователя, но не возвращает другое поле. В приведенном выше примере я хотел бы вернуть [email][address]поле для RMS и [facebook][address]поле для Zuckerburg. Это то, что я пытался найти, если поле имеет значение NULL, но, похоже, оно не работает.

 .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");
      }
    }
  }
Бульбазавр, лишенный сна
источник

Ответы:

90

Я не совсем понимаю, что вы имеете в виду под «возвратом поля», но вы можете использовать lean()запрос, чтобы вы могли свободно изменять вывод, затем заполнять оба поля и постобработать результат, чтобы сохранить только нужное вам поле:

.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
источник
1
это не работает для меня, кто-нибудь знает, изменилось ли это с обновлением Mongoose?
Ninja Coding
1
Это не работает для меня тоже, я пытался .populate('model', 'field'), .populate('model', { field: 1}), .populate('model', [field])с и без lean()и с и без selectPopulatedPaths: falseна модели , но у меня всегда полный заполненный объект в ответ. В документации сказано, что ваш ответ должен быть правильным, но я не могу заставить его работать. У кого-то такая же проблема?
mel-mouk
54

Если вы хотите, чтобы для заполненных документов возвращалось только несколько определенных полей, вы можете сделать это, передав синтаксис имени поля в качестве второго аргумента методу заполнения.

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

См. Раздел " Выбор поля заполнения мангуста"

не упоминать
источник
8
Работает отлично. Вы также можете вернуть больше полей, только вы должны передать больше полей. -> populate ('the_field_to_populate', 'name lastname')
slorenzo
Что, если бы у вас было несколько моделей для заполнения и вам нужны поля для них? Как заполнить ("сообщения пользователей", "имя")? Вы бы назвали обоих?
MoDrags
Примерно так: Model.findOne ({_ id: 'foo'}). Populate ({path: 'parent-model', populate: {path: 'someProperty', populate: {path: 'somePropertyBelow'}}})
dontmentionthebackup
28

Попробуйте сделать это:

User.find(options, '_id user email facebook').populate('facebook', '_id pos').exec(function (err, users) {
Scuencag
источник
26

Попробуйте сделать это:

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);
}
S Kumar
источник
1
Просто чтобы немного объяснить, что здесь происходит: это для выбора полей во вложенном заполнении и в простом заполнении.
Андре Саймон
Ты спас мне день :)
Пешрав Х. Ахмед
23

Теперь вы можете:

  .populate('friends', { username: 1, age: 1})
Скаро
источник
Вы спасли мой день
Thamaraiselvam
4

вам попробовать:

Post.find({_id: {$nin: [info._id]}, tags: {$in: info.tags}}).sort({_id:-1})
.populate('uid','nm')
.populate('tags','nm')
.limit(20).exec();
Тран Хоанг Хип
источник
2

Чтобы дополнить приведенные выше ответы, если вы хотите включить все, но исключить только определенные атрибуты , вы можете сделать следующее:

.populate('users', {password: 0, preferences: 0})
Прашант Гимире
источник
0

Привет, для меня это сработало, я заполнил поле пользователя, используя код заполнения: --->

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)
    }
}

я напрямую получаю результат. Здесь поля userName, userProfile image - это те поля, которые требуются выборочно, а синтаксис для заполнения: ->

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

каждый параметр должен быть в кавычках.

Ниже приведен результат, который я получаю. Еще одна вещь, которую вам не нужно беспокоиться о заполнении идентификатора вложенного документа, вы получите автоматически.

[
    {
        "_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
    }
]
Панкай Шукла
источник
0

В следующем запросе я извлек статьи, которые соответствуют условию, show=trueполученные данные title and createdAt также извлекают категорию статьи, только название категории и ее идентификатор.

let articles = await articleModel
        .find({ show: true }, { title: 1, createdAt: 1 })
        .populate("category", { title: 1, _id: 1 });
Ахмед Махмуд
источник
-1

вы можете попробовать использовать ниже,

 Model
    .find()
    .populate({path: 'foreign_field', ['_id', 'name']}) // only return the Id and Persons name
    ...
Нареш Рамолия
источник