Devuelve ciertos campos con .populate () de Mongoose

82

Recibo un valor JSON de MongoDB después de ejecutar mi consulta. El problema es que no quiero devolver todo el JSON asociado con mi devolución, intenté buscar en los documentos y no encontré una forma adecuada de hacerlo. Me preguntaba qué pasa si es posible y, de ser así, cuál es la forma correcta de hacerlo. Ejemplo: en la base de datos

{
    user: "RMS",
    OS: "GNU/HURD",
    bearded: "yes",
    philosophy: {
        software: "FOSS",
        cryptology: "Necessary"
    },
    email: {
        responds: "Yes",
        address: "[email protected]"
    },
    facebook: {}
}

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

¿Cuál sería la forma correcta de devolver un campo si existe para un usuario, pero si no devuelve otro campo? Para el ejemplo anterior, me gustaría devolver el [email][address]campo para RMS y el [facebook][address]campo para Zuckerburg. Esto es lo que he intentado encontrar si un campo es nulo, pero parece que no funciona.

 .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");
      }
    }
  }
Bulbasaur privado de sueño
fuente

Respuestas:

89

No tengo muy claro lo que quiere decir con "devolver un campo", pero puede usar una lean()consulta para poder modificar libremente la salida, luego completar ambos campos y procesar posteriormente el resultado para mantener solo el campo que desea:

.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
fuente
1
esto no funciona para mí, ¿alguien sabe si esto ha cambiado con una actualización de Mongoose?
Codificación Ninja
1
Esto no está funcionando para mí tampoco, he intentado .populate('model', 'field'), .populate('model', { field: 1}), .populate('model', [field])con y sin lean()y con y sin selectPopulatedPaths: falseel modelo, pero siempre me dieron el objeto poblada completa en la respuesta. La documentación dice que se supone que su respuesta es la correcta, pero no puedo hacer que funcione. ¿Alguien tiene el mismo problema?
mel-mouk
51

Si solo desea que se devuelvan algunos campos específicos para los documentos rellenados, puede hacerlo pasando la sintaxis del nombre del campo como segundo argumento del método rellenar.

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

Ver selección de campo poblado de mangosta

no mencionar la copia de seguridad
fuente
7
Funciona bien. También puede devolver más campos, solo que debe pasar más campos. -> populate ('the_field_to_populate', 'nombre apellido')
slorenzo
¿Qué pasaría si tuviera más de un modelo para completar y quisiera campos para esos? ¿Como poblar ('publicaciones de usuarios', 'nombre')? ¿Conseguirías nombres para ambos?
MoDrags
Algo como esto: Model.findOne ({_ id: 'foo'}). Populate ({path: 'parent-model', populate: {path: 'someProperty', populate: {path: 'somePropertyBelow'}}})
dontmentionthebackup
28

Intenta hacer esto:

User.find(options, '_id user email facebook').populate('facebook', '_id pos').exec(function (err, users) {
scuencag
fuente
24

Intenta hacer esto:

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
fuente
Solo para explicar un poco lo que está sucediendo aquí: esto es para seleccionar campos en un poblado anidado y en un poblado simple.
Andre Simon
Me salvaste el día :)
Peshraw H. Ahmed
21

Ahora lo que puedes hacer es:

  .populate('friends', { username: 1, age: 1})
Scaraux
fuente
me salvaste el día
Thamaraiselvam
3

que intente:

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
fuente
2

Solo para complementar las respuestas anteriores, si desea incluir todo pero solo excluir ciertos atributos , puede hacer lo siguiente:

.populate('users', {password: 0, preferences: 0})
Prashant Ghimire
fuente
0

Hola para mí, funcionó para mí, completé el campo de usuario usando el código de llenado: --->

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

obtengo directamente el resultado. Aquí los campos userName, userProfile image son los que he requerido de forma selectiva y la sintaxis para rellenar es: ->

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

cada parámetro debe estar entre comas invertidas.

A continuación se muestra el resultado que recibo. Una cosa más que no tiene que preocuparse por la identificación del subdocumento de llenado, los obtendrá automáticamente.

[
    {
        "_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
    }
]
Pankaj Shukla
fuente
0

En la siguiente consulta, recuperé artículos que coinciden con la condición, show=truelos datos title and createdAt recuperados también recuperan la categoría del artículo solo el título de la categoría y su identificación.

let articles = await articleModel
        .find({ show: true }, { title: 1, createdAt: 1 })
        .populate("category", { title: 1, _id: 1 });
Ahmed Mahmoud
fuente
-1

puedes probar a usar a continuación,

 Model
    .find()
    .populate({path: 'foreign_field', ['_id', 'name']}) // only return the Id and Persons name
    ...
Naresh Ramoliya
fuente