Comment transformer un document Mongoose en objet simple?

200

J'ai un document d'une mangouste que je souhaite étendre avant l'encodage JSON et l'envoyer comme réponse. Si j'essaie d'ajouter des propriétés au document, il est ignoré. Les propriétés n'apparaissent pas en Object.getOwnPropertyNames(doc)rendant impossible une extension normale. La chose étrange est que cela JSON.parse(JSON.encode(doc))fonctionne et renvoie un objet avec toutes les propriétés correctes. Y a-t-il une meilleure manière de faire cela?

respectTheCode
la source

Réponses:

292

Les mangoustes Modelhéritent de Documents, qui ont une toObject()méthode. Je crois que ce que vous cherchez devrait être le résultat de doc.toObject().

http://mongoosejs.com/docs/api.html#document_Document-toObject

jmar777
la source
1
je l'ai finalement eu. pour ceux qui ne doivent pas définir l'objet, assurez-vous d'appeler le document au lieu du modèle. ie modelName._doc.toObject ()
John
1
C'est OK mais lean () est préférable.
Jason Sebring
Est-ce que cela fonctionne si vous retournez un tableau sur Model.find({})le retour de documents est un tableau. Pouvez-vous docs.toObject?
jack blank
5
@jackblank si vous avez un éventail de modèles, vous devriez pouvoir les cartographier:var docArray = modelArray.map(function(model) { return model.toObject(); });
jmar777
@ jmar777 je pense que votre suggestion appartient en tant que modification à cette réponse.
r3wt
201

Une autre façon de le faire est de dire à Mongoose que tout ce dont vous avez besoin est une version JavaScript simple du document renvoyé en utilisant lean()dans la chaîne de requête. De cette façon, Mongoose ignore l'étape de création de l'instance de modèle complète et vous obtenez directement un que docvous pouvez modifier:

MyModel.findOne().lean().exec(function(err, doc) {
    doc.addedProperty = 'foobar';
    res.json(doc);
});
JohnnyHK
la source
17
@Startec Using leanest généralement plus performant car vous ignorez la surcharge de création initiale du document Mongoose complet.
JohnnyHK
3
vous êtes un champion :) corrigez-moi si je me trompe, mais vous devriez toujours appuyer () vos trouvailles si vous n'avez pas l'intention de modifier et d'enregistrer le document que vous venez de recevoir (par exemple, si vous essayez simplement d'accéder à la doc et renvoyez-le à votre client)
Amarsh
1
@Amarsh Oui, bien que cela suppose également que vous n'avez besoin d'aucune des méthodes d'instance ou des virtuels définis dans le schéma.
JohnnyHK
1
bizzare cependant ... cela aurait pu être une option avec find () ... il est souvent trop courant de lire un document à partir d'un mongodb et de le renvoyer à un navigateur Web. je me demande si trouver (). lui-même.
Amarsh
4
@Amarsh Non, le chaînage lean()de la requête définit l'option avant que la requête ne soit réellement exécutée (par exec) afin que les résultats soient directement sous leur forme "allégée". Consultez cette question pour connaître l'impact positif sur les performances de l'appel lean.
JohnnyHK
29

la manière rapide si la propriété n'est pas dans le modèle:

document.set( key,value, { strict: false });

alban maillere
la source
5
oui ... et aussi surprenant que cela puisse paraître, je pense toujours que cela pourrait être utile. Par exemple, vous conservez toutes les primitives de votre objet.
alban maillere
Merci pour cette réponse, c'était ce que je cherchais :)
datUser
6

Une meilleure façon d'aborder un problème comme celui-ci consiste à utiliser doc.toObject()comme ceci

doc.toObject({ getters: true })

les autres options incluent:

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

Ainsi, par exemple, vous pouvez dire

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

et maintenant ça va marcher.

Pour référence, voir: http://mongoosejs.com/docs/api.html#document_Document-toObject

Jalasem
la source
3

Pour obtenir un objet simple à partir du document Mongoose, j'ai utilisé la _docpropriété comme suit

mongooseDoc._doc  //returns plain json object

J'ai essayé avec toObjectmais ça m'a donné des fonctions, des arguments et toutes autres choses dont je n'ai pas besoin.

dd619
la source
3
Accéder aux propriétés ou aux méthodes avec _au début ce n'est pas la solution idéale. L'utilisation de Lean pourrait résoudre votre cas.
Arthur Costa
@ArthurBrito oui. Ce n'est pas une solution idéale mais c'est quand même une SOLUTION! . Pas besoin de dévaloriser la réponse. J'ai utilisé la _docpropriété plusieurs fois sans faire face à aucun problème. Et l'utilisation de la leanméthode vous donne un objet simple sur lequel vous ne pouvez pas effectuer d'opérations sur le modèle mangouste.
dd619
vous avez raison. Ajoutez simplement votre réponse qui n'est pas la solution idéale, puis je supprimerai le downvote (je ne peux pas le supprimer à moins que vous n'ayez modifié)
Arthur Costa
2

Vous pouvez également stringifier l'objet, puis à nouveau analyser pour créer l'objet normal. Par exemple, comme: -

const obj = JSON.parse(JSON.stringify(mongoObj))
kaushik_pm
la source