I have some MongoDB documents with this schema:
Id: {type: "id", key: true, computed: true, nullable: false},
Name: {type: "string", nullable: false, maxLength: 50}
and these documents are exposed as OData by a small web application (I'm using Express, JayData, and Mongoose).
These are some of those documents:
{ "_id" : ObjectId("5343fd656b9c5c084b8f2a70"), "Name" : "Service74"},
{ "_id" : ObjectId("5343fd656b9c5c084b8f2a6f"), "Name" : "Service73"},
{ "_id" : ObjectId("5343fd656b9c5c084b8f2a6e"), "Name" : "Service72"},
...
If I type this address http://localhost:8080/marketplace/Services('5343fd656b9c5c084b8f2a70') which correspond to Service74 I get this result:
...
<d:Id>NTM0M2ZkNjU2YjljNWMwODRiOGYyYTcw</d:Id>
<d:Name>Service74</d:Name>
...
Of course If I use the Id specified in the result I obtain the same page.
The problem occurs when I try to use the mongoose function findById:
app.post("/addCompare/:id", function(req, res) {
console.log(req.params.id);
Services.findById(req.params.id, function(err, service) {
if(!err) {console.log(service);}
else {console.log(err);}
});
res.send(200);
});
I get this NTM0M2ZkNjU2YjljNWMwODRiOGYyYTcw and then this error:
{ message: 'Cast to ObjectId failed for value "NTM0M2ZkNjU2YjljNWMwODRiOGYyYTU5" at path "_id"',
name: 'CastError',
type: 'ObjectId',
value: 'NTM0M2ZkNjU2YjljNWMwODRiOGYyYTU5',
path: '_id' }
Where am I wrong? Tell me if I miss some other information...
Thanks.
PS: I found a similar problem here Mongoose: Cast to ObjectId failed, but if I change the model definition for Mongoose (in which actually I don't declare the id) by including this definition:
var serviceSchema = mongoose.Schema({
_id: String,
...
nothing changes...
The 5343fd656b9c5c084b8f2a70 is the internal identifier of the entity that is used on the server-side. This value is base64-encoded over OData, this is why you receive NTM0M2ZkNjU2YjljNWMwODRiOGYyYTcw in the Id field. The entity can be easily retrieved by Id by calling atob(req.params.id) on the received Id.
Related
I have one schema like this:
export const HotelSchema = new mongoose.Schema({
name: String,
firstName: String,
email: { type: String, unique: true },
canLogin: Boolean
},
{
collection: "hotels"
}
);
and to add/update I am using this query:
this.hotelModel.updateOne({ _id: hotel._id }, hotel, { upsert: true });
Where hotel object I am passing:
{
"email" : "er.markar#gmail.com",
"name" : "sunny123"
}
But it is inserting duplicate emails with _id as null:
Even I tried findOneAndUpdate. tried autoIndex in the email schema. Still not working.
Am I missing something?
See https://mongoosejs.com/docs/validation.html#the-unique-option-is-not-a-validator
Infact, you should use unique index on a field. That works!
You are passing email and name, but you are not passing "_id", so "hotel._id" will not be found. Instead you should do as follows:
this.hotelModel.updateOne({ email:hotel.email}, hotel, { upsert:true});
I need to define the mongoose schema for for nested documents which is given below.
Documents:
"Options":[{"Value":["28","30","32","34","36","38","40","42","44","46"],"_id":{"$oid":"5de8427af55716115dd43c8f"},"Name":"Size"},{"Value":["White"],"_id":{"$oid":"5de8427af55716115dd43c8e"},"Name":"Colour"}]
I was declaring like below but its not working.
const Product = new Schema(
{
Options: [{ value: { _id: ObjectId, Name: String } }]
},
{
timestamps: {
createdAt: "createdAt",
updatedAt: "updatedAt"
},
collection: "products"
}
);
Here I need the schema where if i will directly add/update the same document then it will be added.
You need to modify your schema like this :
{
Options: [ new Schema ({ value: [...], _id: Schema.Types.ObjectId, Name: String })]
}
This is the way to create an array of subdocuments with Mongoose. If you don't use the "new Schema" key words, you are actually creating a field with type "Mixed", which needs a different way to handle updates.
You can also omit the _id, it should be added automatically.
You can find more information on subdocument on this page :
https://mongoosejs.com/docs/subdocs.html
...and on mixed type fields : https://mongoosejs.com/docs/schematypes.html#mixed
...which will explain shortly the problem.
{
Options: [ new Schema ({ _id: mongoose.Types.ObjectId(),value: [String], Name: String } })]
}
I have an array of numbers. I'd like to compare each item in the array to all the values for a particular key of a collection. Is that possible? In the example below, I'd grab only those objects that have an id of 05,07,21,36,and 42.. but this attempt fails -
var playlist =[05,07,21,36,42]
The query:
Track.find({ id: playlist })...
The collection:
artist:{type: String},
title: {type: String},
id: {type: String}...
The property is actually "_id" -- Track.find({ "_id": {$in: playlist} }) -- and when I tried this, I was returned the error printed below. Any ideas?
message: 'Cast to ObjectId failed for value "597e2f68c83f5d5ba6723427,597e2f68c83f5d5ba6723429,597e2f68c83f5d5ba672342c,597e2f68c83f5d5ba6723429,597e2f68c83f5d5ba672342c,597e2f68c83f5d5ba672342b,597e2f68c83f5d5ba672342d" at path "_id" for model "Track"',
name: 'CastError',
stringValue: '"597e2f68c83f5d5ba6723427,597e2f68c83f5d5ba6723429,597e2f68c83f5d5ba672342c,597e2f68c83f5d5ba6723429,597e2f68c83f5d5ba672342c,597e2f68c83f5d5ba672342b,597e2f68c83f5d5ba672342d"',
kind: 'ObjectId',
value: '597e2f68c83f5d5ba6723427,597e2f68c83f5d5ba6723429,597e2f68c83f5d5ba672342c,597e2f68c83f5d5ba6723429,597e2f68c83f5d5ba672342c,597e2f68c83f5d5ba672342b,597e2f68c83f5d5ba672342d',
path: '_id',
You need to use $in. Try Track.find({ id: { $in: playlist } })
See Mongo $in Operator
If you have subdocument arrays, Mongoose automatically creates ids for each one. Example:
{
_id: "mainId"
subDocArray: [
{
_id: "unwantedId",
field: "value"
},
{
_id: "unwantedId",
field: "value"
}
]
}
Is there a way to tell Mongoose to not create ids for objects within an array?
It's simple, you can define this in the subschema :
var mongoose = require("mongoose");
var subSchema = mongoose.Schema({
// your subschema content
}, { _id : false });
var schema = mongoose.Schema({
// schema content
subSchemaCollection : [subSchema]
});
var model = mongoose.model('tablename', schema);
You can create sub-documents without schema and avoid _id. Just add _id: false to your subdocument declaration.
var schema = new mongoose.Schema({
field1: {
type: String
},
subdocArray: [{
_id: false,
field: { type: String }
}]
});
This will prevent the creation of an _id field in your subdoc.
Tested in Mongoose v5.9.10
Additionally, if you use an object literal syntax for specifying a sub-schema, you may also just add _id: false to supress it.
{
sub: {
property1: String,
property2: String,
_id: false
}
}
I'm using mongoose 4.6.3 and all I had to do was add _id: false in the schema, no need to make a subschema.
{
_id: ObjectId
subDocArray: [
{
_id: false,
field: "String"
}
]
}
You can use either of the one
var subSchema = mongoose.Schema({
//subschema fields
},{ _id : false });
or
var subSchema = mongoose.Schema({
//subschema content
_id : false
});
Check your mongoose version before using the second option
If you want to use a predefined schema (with _id) as subdocument (without _id), you can do as follow in theory :
const sourceSchema = mongoose.Schema({
key : value
})
const subSourceSchema = sourceSchema.clone().set('_id',false);
But that didn't work for me. So I added that :
delete subSourceSchema.paths._id;
Now I can include subSourceSchema in my parent document without _id.
I'm not sure this is the clean way to do it, but it work.
NestJS example for anyone looking for a solution with decorators
#Schema({_id: false})
export class MySubDocument {
#Prop()
id: string;
}
Below is some additional information from the Mongoose Schema Type definitions for id and _id:
/**
* Mongoose assigns each of your schemas an id virtual getter by default which returns the document's _id field
* cast to a string, or in the case of ObjectIds, its hexString.
*/
id?: boolean;
/**
* Mongoose assigns each of your schemas an _id field by default if one is not passed into the Schema
* constructor. The type assigned is an ObjectId to coincide with MongoDB's default behavior. If you
* don't want an _id added to your schema at all, you may disable it using this option.
*/
_id?: boolean;
var myschema = new Schema({
name: {type:String, default:'fullname'},
subdoc: {
day1: {type:Array, default:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},
day2: {type:Array, default:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}
}
});
var mymodel = Mongoose.model('mytest',myschema);
//mongoose 3.5.6: find
mymodel.find({},{'name'}, function(err,docs){
logger.info("---> " + docs);
});
results:
---> { _id: 512da190ba48050f2e000001, **subdoc: {}**, name: 'fullname' }
Only name field is requested to be returned, but this function always returns subdoc: {}. Can someone explain this?
use mongodb shell, it looks fine
db.mytests.find({},{"name":1})
{ "_id" : ObjectId("512da190ba48050f2e000001"), "name" : "fullname" }
Then I change the model to:
var myschema = new Schema({
name: {type:String, default:'fullname'},
subdoc: [
day1: {type:Array, default:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},
day2: {type:Array, default:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}
] // **note: not {} here**
})
use the same mongoose api find, the result is just what I expected:
--->{ _id: 512da46fffebd24b30000002, name: 'fullname' }
My questions is: Why field 'subdoc' is returned with the former schema?
According to the docs, it appears as if you are a little bit off.
Example:
// name LIKE john and only selecting the "name" and "friends" fields, executing immediately
MyModel.find({ name: /john/i }, 'name friends', function (err, docs) { })
With that, I would do something like this:
myModel.find( {}, 'name', callback);
Edit
To address your comments: In mongodb console, the proper way to format it would be {'name':1, 'friend':1}. Using:
db.collection.find({}, {'name friend'})
will throw an error. To do this properly, you would do:
db.collection.find({}, {'name':1, 'friend':1})
However, if you prefer this way of field selection, mongoose does allow you to do that as well.
myModel.find({}, {'name':1, 'friend': 1}, callback);
See: API Docs