web-dev-qa-db-fra.com

Les champs de résultats Mongoose/MongoDB ne sont pas définis en Javascript

Y at-il quelque chose qui me manque qui permettrait à l'élément de se connecter en tant qu'objet avec un paramètre, mais lorsque j'essaie d'accéder à ce paramètre, il n'est pas défini?

Ce que j'ai essayé jusqu'à présent:

  • console.log(item) => { title: "foo", content: "bar" }, c'est bon
  • console.log(typeof item) => objet
  • console.log(item.title) => "undefined"

Je vais inclure une partie du contexte au cas où il serait pertinent au problème.

var TextController = function(myCollection) {
  this.myCollection = myCollection
}

TextController.prototype.list = function(req, res, next) {
  this.myCollection.find({}).exec(function(err, doc) {
    var set = new Set([])
    doc.forEach(function(item) {
      console.log(item)         // Here item shows the parameter
      console.log(item.title)   // "undefined"
      set.add(item.title)       
    })
    res.json(set.get());
  })
}

Sur la base de la suggestion, j'ai laissé debugger avant cette ligne pour vérifier quel élément est réellement via le débogueur de noeud. C'est ce que j'ai trouvé: http://hastebin.com/qatireweni.sm

A partir de cela, j'ai essayé console.log(item._doc.title) et cela fonctionne très bien .. Donc, cela ressemble plus à une question de mangouste maintenant qu'à autre chose.

Il y a des questions similaires à celles-ci, mais elles semblent être liées à «cet» accès aux objets ou ils essaient de faire sortir l'objet de la portée de la fonction. Dans ce cas, je ne pense pas que je fais quoi que ce soit, mais informez-moi si je me trompe. Merci

24
tippenein

Solution

Vous pouvez appeler la méthode toObject pour accéder aux champs. Par exemple:

var itemObject = item.toObject();
console.log(itemObject.title); // "foo"

Pourquoi

Comme vous le soulignez, les champs réels sont stockés dans le champ _doc du document.

Mais pourquoi console.log(item) => { title: "foo", content: "bar" }?

De le code source de mongoose (document.js) , nous pouvons constater que la méthode toString de Document appelle la méthode toObject. Donc, console.log affichera les champs 'correctement'. Le code source est indiqué ci-dessous:

var inspect = require('util').inspect;

...

/**
 * Helper for console.log
 *
 * @api public
 */
Document.prototype.inspect = function(options) {
  var isPOJO = options &&
    utils.getFunctionName(options.constructor) === 'Object';
  var opts;
  if (isPOJO) {
    opts = options;
  } else if (this.schema.options.toObject) {
    opts = clone(this.schema.options.toObject);
  } else {
    opts = {};
  }
  opts.minimize = false;
  opts.retainKeyOrder = true;
  return this.toObject(opts);
};

/**
 * Helper for console.log
 *
 * @api public
 * @method toString
 */

Document.prototype.toString = function() {
  return inspect(this.inspect());
};
30
Vincent Bel

Assurez-vous que vous avez défini le titre dans votre schéma:

var MyCollectionSchema = new mongoose.Schema({
    _id: String,
    title: String
});
7

Essayez d’effectuer une boucle for in sur item et voyez si vous pouvez accéder aux valeurs.

for (var k in item) {
    console.log(item[k]);
}

Si cela fonctionne, cela signifie que vos clés ont des caractères non-printable ou quelque chose comme ça.

D'après ce que vous avez dit dans les commentaires, il semblerait que item soit une instance d'un wrapper primitif String.

Par exemple. 

var s = new String('test');
typeof s; //object
s instanceof String; //true

Pour vérifier cette théorie, essayez ceci:

eval('(' + item + ')').title;

Il se peut également que item soit un objet doté d'une méthode toString qui affiche ce que vous voyez.

EDIT: Pour identifier rapidement ces problèmes, vous pouvez utiliser console.dir au lieu de console.log, car il affiche une liste interactive des propriétés de l’objet. Vous pouvez également mais un point d'arrêt et ajouter une montre.

4
plalx

Je pense que l’utilisation de la méthode 'find' renvoie un tableau de documents. J’ai essayé cela et j’ai pu imprimer le titre.

for (var i = 0; i < doc.length; i++) {
   console.log("iteration " + i);
   console.log('ID:' + docs[i]._id);
   console.log(docs[i].title);
}
2
bertanasco

Vous n'avez pas d'espaces ni de caractères amusants dans ' title', n'est-ce pas? Ils peuvent être définis si vous avez cité des identificateurs dans la définition d'objet/de carte. Par exemple:

var problem = {
    ' title': 'Foo',
    'content': 'Bar'
};

Cela pourrait entraîner l'affichage de console.log(item) similaire à ce que vous attendez, mais le problème undefined lorsque vous accédez à la propriété title sans l'espace précédent.

2
Thomas W

Vieille question, mais comme j'ai eu un problème avec ça aussi, je vais y répondre.
Ceci est probablement dû au fait que vous utilisez find() au lieu de findOne(). En fin de compte, vous appelez une méthode pour un tableau de documents au lieu d'un document, ce qui aboutit à la recherche d'un tableau et non d'un document unique. Utiliser findOne() vous permettra d’obtenir un accès normal à l’objet.

2
user5887278

Si vous souhaitez uniquement obtenir les informations sans bénéficier de tous les avantages de la mangouste, sauvegardez, c.-à-d., Vous pouvez utiliser .lean () dans votre requête. Vos informations seront plus rapides et vous pourrez les utiliser directement en tant qu'objet.

https://mongoosejs.com/docs/api.html#query_Query-lean

Comme indiqué dans la documentation, il s'agit du meilleur choix pour les scénarios en lecture seule.

1
LordRasta

Utilisez findOne() au lieu de find().

La méthode find() renvoie un tableau de valeurs. Même si vous n'avez qu'un seul résultat possible, vous devrez utiliser l'élément [0] pour l'obtenir.

La méthode findOne renvoie un objet ou aucun, vous pourrez alors accéder à ses propriétés sans aucun problème.

1
George

Êtes-vous en train d'initialiser votre objet?

function MyObject()
{
    this.Title = "";
    this.Content = "";
}

var myo1 = new MyObject();

Si vous n’initialisez pas ou n’avez pas défini de titre. Vous serez indéfini.

0
Valamas

Une meilleure façon de traiter un problème de ce type consiste à utiliser doc.toObject() comme ceci.

doc.toObject({ getters: true })

d'autres options incluent:

  • getters: applique tous les getters (chemin et getters virtuels)
  • virtuals: appliquer des getters virtuels (peut remplacer l'option de getters)
  • minimize: supprime les objets vides (par défaut, true)
  • transform: une fonction de transformation à appliquer au document résultant avant de renvoyer
  • depopulate: dépeupler les chemins remplis, en les remplaçant par leurs références d'origine (par défaut, false)
  • versionKey: s'il faut inclure la clé de version (true par défaut)

ainsi, par exemple, vous pouvez dire 

Model.findOne().exec((err, doc) => {
   if (!err) {
      doc.toObject({ getters: true })
      console.log('doc _id:', doc._id) // or title
   }
})

et maintenant ça va marcher

0
Jalasem