web-dev-qa-db-fra.com

Mongoose: CastError: Echec de la conversion en ObjectId pour la valeur "[objet Object]" sur le chemin "_id"

Je suis nouveau sur node.js, j'ai donc le sentiment que c'est une bêtise que j'ai négligée, mais je n'ai pas été en mesure de trouver une réponse qui résolve mon problème. Ce que j'essaie de faire est de créer un chemin qui créera un nouvel objet enfant, l'ajoutera au tableau d'enfants du parent, puis renverra l'objet enfant au demandeur. Le problème que je rencontre est que si je passe l'id de la chaîne à findById, le noeud plante avec

TypeError: L'objet {} n'a pas de méthode 'cast'

Si j'essaie plutôt de passer un ObjectId, j'obtiens

CastError: Echec de la conversion en ObjectId pour la valeur "[objet Object]" sur le chemin "_id"

Voici un aperçu de mon code:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId; //Have also tried Schema.Types.ObjectId, mongoose.ObjectId

mongoose.connect('mongodb://user:password@server:port/database');

app.get('/myClass/:Id/childClass/create', function(request, result) {
  var id = new ObjectId(request.params.Id);
  MyClass.findById(id).exec( function(err, myClass) {
    if (err || !myClass) { result.send("error: " + err + "<br>" + JSON.stringify(id) || ("object '" + request.params.Id + "' not found: " + id)); return; }
    var child = ChildClass();
    myClass.Children.addToSet(child);
    myClass.save();
    result.send(child);
  });
});

Si j'exécute ce code avec le chemin "/ myClass/51c35e5ced18cb901d000001/childClass/create", il s'agit de la sortie du code:

error: CastError: Echec de la conversion vers ObjectId pour la valeur "[objet Object]" sur le chemin "_id" {"path": "51c35e5ced18cb901d000001", "instance": "ObjectID", "validators": [], "setters": [], "getters": [], "_ index": null}

J'ai essayé d'utiliser findOne et de passer {_id: id} à la place, mais cela semble être exactement ce que fait FindById. J'ai essayé les différentes classes pour ObjectId que j'ai vues énumérées sur d'autres sites. J'ai essayé d'appeler ObjectId () comme une fonction au lieu d'un constructeur et cela retourne undefined. À ce stade, je suis à court d'idées et il ne semble pas que rechercher une réponse sur Google puisse aider. Des idées sur ce que je fais mal?

En outre, comme je l’ai dit, je connais pour la première fois noeud/Mongo/Mongoose/Express. Par conséquent, s’il existe un meilleur moyen d’atteindre mon objectif, merci de me le faire savoir. J'apprécie tous les commentaires.

MODIFIER:

Après la solution de rechange de Peter Lyons, j’ai cherché dans une autre erreur que j’étais en train de chercher et ai trouvé findByIdAndUpdate, qui fonctionne comme prévu et fait exactement ce que j’espérais faire. Je ne suis toujours pas sûr de savoir pourquoi findById et findOne me causaient de tels problèmes et je suis curieux de savoir (peut-être qu'un rapport de bogue doit être rédigé), je vais donc laisser cette option ouverte au cas où quelqu'un d'autre aurait une réponse.

38
jmblackmer

Réponse courte: utilisez mongoose.Types.ObjectId.

Mongoose (mais pas mongo) peut accepter les identifiants d'objet en tant que chaînes et les "caster" correctement pour vous, utilisez donc simplement:

MyClass.findById(req.params.id)

Toutefois, si req.params.id n’est pas un format valide pour une chaîne d’identification mongo, cela générera une exception que vous devez saisir.

La principale source de confusion à comprendre est que mongoose.SchemaTypes contient des éléments que vous utilisez uniquement lors de la définition de schémas mangouste et que mongoose.Types contient ceux que vous utilisez pour créer des objets de données que vous souhaitez stocker dans la base de données ou des objets de requête. Donc, mongoose.Types.ObjectId("51bb793aca2ab77a3200000d") fonctionne, vous donnera un objet que vous pouvez stocker dans la base de données ou à utiliser dans des requêtes, et lèvera une exception si une chaîne d'identifiant invalide est donnée.

findOne prend un objet de requête et transmet une instance de modèle unique au rappel. Et findById est littéralement un wrapper de findOne({_id: id}) ( voir le code source ici ). Juste find prend un objet de requête et passe un tableau d'instances de modèle correspondantes au rappel.

Allez-y doucement. C'est déroutant, mais je peux vous garantir que vous êtes en train de devenir confus et que vous ne rencontrez pas d'insectes chez la mangouste pour le moment. C'est une bibliothèque assez mature, mais il faut un certain temps pour bien la comprendre.

L'autre chose suspecte que je vois dans votre extrait de code n'utilise pas new lors de l'instanciation de ChildClass. Au-delà de cela, vous devrez publier votre code de schéma pour que nous puissions vous aider à localiser les éventuels erreurs restantes de CastErrors.

56
Peter Lyons

J'ai rencontré cette erreur, car la valeur que vous souhaitez filtrer dans le champ _id n'est pas au format ID, un "if" devrait résoudre ce problème.

const mongoose = require('mongoose');

console.log(mongoose.Types.ObjectId.isValid('53cb6b9b4f4ddef1ad47f943'));
// true
console.log(mongoose.Types.ObjectId.isValid('whatever'));
// false

Pour le résoudre, toujours valider si la valeur du critère de recherche est un ObjectId valide.

if(params.q) {
  criteria.$or = []
  if(mongoose.Types.ObjectId.isValid(params.id)) {
    criteria.$or.Push({ _id: params.q })
  }
  criteria.$or.Push({ name: { $regex: params.q, $options: 'i' }})
  criteria.$or.Push({ email: { $regex: params.q, $options: 'i' }})
  criteria.$or.Push({ password: { $regex: params.q, $options: 'i' }})
}

return UserModule.find(criteria).exec(() => {
  // do stuff
})
16
gsalgadotoledo

Pour toutes ces personnes qui étaient coincées dans ce problème mais qui ne pouvaient toujours pas le résoudre: je suis tombé sur la même erreur et j'ai trouvé le champ _id vide.

Je l'ai décrit ici plus en détail. Je n'ai toujours pas trouvé de solution, sauf en remplaçant les champs de _id par des champs non-ID, ce qui est un sale bidouillage. Je vais probablement déposer un rapport de bogue pour la mangouste. Toute aide serait appréciée!

Edit: j'ai mis à jour mon fil. J'ai classé un billet et ils ont confirmé le problème manquant de _id. Il va être corrigé dans la version 4.x.x qui a une version candidate disponible actuellement. Le rc n'est pas recommandé pour une utilisation productive!

3
Stefan Medack

Si vous rencontrez ce problème et que vous effectuez une opération de peuplement dans le même sens, voir ce problème Mongoose .

Mettez à jour Mongoose 4.0 et le problème a été corrigé.

2
ac360

Ayant le même problème, j'ai juste forcé l'identifiant dans une chaîne.

Mon schéma:

const product = new mongooseClient.Schema({
    retailerID: { type: mongoose.SchemaTypes.ObjectId, required: true, index: true }
});

Et puis, lors de l'insertion:

retailerID: `${retailer._id}`
2
camstuart

Je recevais cette erreur CastError: la conversion vers ObjectId a échoué pour la valeur “[objet Object]” sur le chemin “_id” après avoir créé un schéma, puis l'a modifié et ne pouvait pas le retrouver. J'ai supprimé tous les documents de la collection et je pouvais ajouter un objet mais pas un second. J'ai fini par supprimer la collection à Mongo et cela a fonctionné lorsque Mongoose a recréé la collection.

1
Enkode

J'avais le même problème. Il s'avère que mon Node.js était obsolète. Après la mise à niveau, cela fonctionne.

1
Rajesh Barik

Pour mémoire: j'ai eu cette erreur en essayant de remplir un sous-document de manière incorrecte:

{
[CastError: Cast to ObjectId failed for value "[object Object]" at path "_id"]
message: 'Cast to ObjectId failed for value "[object Object]" at path "_id"',
name: 'CastError',
type: 'ObjectId',
path: '_id'
value:
  [ { timestamp: '2014-07-03T00:23:45-04:00',
  date_start: '2014-07-03T00:23:45-04:00',
  date_end: '2014-07-03T00:23:45-04:00',
  operation: 'Deactivation' } ],
}

look ^ value est un tableau contenant un objet: faux!

Explication: J'envoyais des données de php à une API node.js de la manière suivante:

$history = json_encode(
array(
  array(
  'timestamp'  => date('c', time()),
  'date_start' => date('c', time()),
  'date_end'   => date('c', time()),
  'operation'  => 'Deactivation'
)));

Comme vous pouvez le voir, $ history est un tableau contenant un tableau. C'est pourquoi Mongoose essaie de remplir _id (ou tout autre champ) avec un tableau plutôt qu'avec un Scheme.ObjectId (ou tout autre type de données). Les oeuvres suivantes:

$history = json_encode(
array(
  'timestamp'  => date('c', time()),
  'date_start' => date('c', time()),
  'date_end'   => date('c', time()),
  'operation'  => 'Deactivation'
));
1
Igor Parra

J'ai aussi rencontré cette erreur mongoose CastError: la conversion vers ObjectId a échoué pour la valeur "583fe2c488cf652d4c6b45d1 \" sur le chemin \"_ id \" pour l'utilisateur modèle

Donc, je lance la commande npm list pour vérifier la version de mongodb et mangouste dans mon répertoire local . Heres the report: ......
......
├── [email protected]
├── [email protected]
..... 

Il semble qu'il y ait un problème avec cette version de Mongodb, alors ce que j'ai fait est de désinstaller et d'essayer d'utiliser une version différente telle que 2.2.16

$ npm uninstall mongodb, cela supprimera mongodb de votre répertoire node_modules. Après cela, installez la version inférieure de mongodb.
$ npm install [email protected]
Enfin, je redémarre l'application et le CastError est parti !!

0
Arman Ortega

il suffit de changer le chemin, cela fonctionnera par exemple 

app.get('/myClass/:Id/childClass/create', function(request, result) .....

changer à 

app.get('/myClass**es**/:Id/childClass/create', function(request, result) .....

Je viens d'ajouter --es-- au chemin (myClass) pour devenir (myClasses)

devrait maintenant fonctionner et ne verra pas cette erreur

0
happyCoder