My Item Schema:
new Schema({
name: {
ka: String,
en: String
}
});
When doing like this:
Item.findOne({}, function(err, item){
item.name = 'wrongtype';
item.save();
});
item's name property is saved to database, despite of fact that name is described as object in schema. Validation is not working. Can you suggest solution? Or explain if it's correct behaviour
Related
I'm trying to use Mongoose (MongoDB JS library) to create a basic database, but I can't figure out how to delete the documents / items, I'm not sure what the technical term for them is.
Everything seems to work fine, when I use Item.findById(result[i].id), it returns a valid id of the item, but when I use Item.findByIdAndDelete(result[i].id), the function doesn't seem to start at all.
This is a snippet the code that I have: (Sorry in advance for bad indentation)
const testSchema = new schema({
item: {
type: String,
required: true
},
detail: {
type: String,
required: true
},
quantity: {
type: String,
required: true
}
})
const Item = mongoose.model("testitems", testSchema)
Item.find()
.then((result) => {
for (i in result) {
Item.findByIdAndDelete(result[i].id), function(err, result) {
if (err) {
console.log(err)
}
else {
console.log("Deleted " + result)
}
}
}
mongoose.connection.close()
})
.catch((err) => {
console.log(err)
})
I'm not sure what I'm doing wrong, and I haven't been able to find anything on the internet.
Any help is appreciated, thanks.
_id is a special field on MongoDB documents that by default is the type ObjectId. Mongoose creates this field for you automatically. So a sample document in your testitems collection might look like:
{
_id: ObjectId("..."),
item: "xxx",
detail: "yyy",
quantity: "zzz"
}
However, you retrieve this value with id. The reason you get a value back even though the field is called _id is because Mongoose creates a virtual getter for 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. If you don't want an id getter added to your schema, you may disable it by passing this option at schema construction time.
The key takeaway is that when you get this value with id it is a string, not an ObjectId. Because the types don't match, MongoDB will not delete anything.
To make sure the values and types match, you should use result[i]._id.
In Mongoose, I have two collections, with one referencing the other. Is it possible to have a find query that selects records based on a value in the other. An example of what I am try to get at (not actual schemas):
const CarModelSchema = new mongoose.Schema({
name: String,
brand: { type: mongoose.Schema.Types.ObjectId, ref: 'CarBrand' }
});
const CarBrandSchema = new mongoose.Schema({
name: String,
country: String
});
I then want to perform a query of the form, without needing to do two queries:
CarModelSchema.find({ 'brand.country': 'GER' });
So far I haven't been able to make this work, so I am wondering whether this can be done in Mongo or whether I am approaching it wrong?
Yes it is possible.
I realize you don't have models for your schemas so add them like this:
const CarModel = mongoose.model('CarModel', CarModelSchema);
const CarBrand = mongoose.model('CarBrand', CarBrandSchema);
Also brands should be defined like this:
brand: [{ type: mongoose.Schema.Types.ObjectId, ref: 'CarBrand' }] //added the brackets
You can then run a find query to filter by country by doing the following:
CarModel.
find(...).
populate({
path: 'brand',
match: { country: { $eq: 'GER' }},
// You can even select the field you want using select like below,
select: 'name -_id',
//Even limit the amount of documents returned in the array
options: { limit: 5 }
}).
exec();
And that should do it, as long as the ObjectIds saved in brands array in the CarModel collection are valid or exist.
Using match in your population will do the work.
CarModel.find()
.populate({
path: 'brand',
model: CarBrandModel,
match: { country: { $eq: 'GER' }},
})
.exec()
Keep in mind you have to define CarModel and CarBrandModel like this:
const CarModel = mongoose.model('CarModel', CarModelSchema)
const CarBrandModel = mongoose.model('CarBrandModel', CarBrandSchema)
Yes, you are doing it wrong.
In CarModelSchema.brand there is not string saved, there is ObjectId saved, therefore you have to find that ObjectId (the reference).
You can do it manually - first finding the CarBrandSchema.find({ 'country': 'GER' }); and then use its ObjectId (=_id), or you can use https://mongoosejs.com/docs/populate.html to populate your CarModel with the CarBrand object.
I am creating a Node app that would need to check the fields of a collection and return what the data type is. For example if the field is "First Name" the data type would be "String". How would I get started creating a back end application that does this?
In case you are using mongoose , then Each field or nested field is addressed by path.
var myschema = new Schema({
...
name: {
first:{type: String, required: true,},
last :{type: String, required: true,},
...
});
here name.first and name.last are paths.
Now to know the type of name.last there is an Schema API, called path().So.
var pathmeta = myschema.path(name.last);
console.log(" datatype = "+pathmeta.instance);
console.log(" whole pathmeta structure is "+JSON.stringify(pathmetas));
should print this..
datatype = String
whole pathmeta structure is
{"enumValues":[],"regExp":null,"path":"text","instance":"String","validators":[],"setters":[],"getters":[],"options":{},"_index":null}
In my Mongoose schema I have an id field which has a unique ID for each document. This runs off the same system used by the default _id field like so:
var JobSchema = new mongoose.Schema({
id: { type:String, required:true, unique:true, index:true, default:mongoose.Types.ObjectId },
title: { type: String },
brief: { type: String }
});
module.exports = mongoose.model("Job", JobSchema);
Now, if I query the schema to get id and title I'd do it like this:
Job.find().select("id title").exec(function(err, jobs) {
if (err) throw err;
res.send(jobs);
});
However, I've found this returns id and title as expected, but it also return the default _id field. Why is that and how do I stop it?
Inside the find() function you can pass two parameters (criteria and projection). Projection are the fields that you want (or not). In your case you can change your code to
Job.find({}, {_id:0, id: 1, title: 1}, function(err, jobs) {
if (err) throw err;
res.send(jobs);
});
and it should do it.
There is an option to prevent the id on schema level.
For me this worked perfectly fine.
new Schema({ name: String }, { id: false });
Mongoose Docs
I have a mongodb running (MEAN environment) with two collections (users and books). One of those collections (myusers) contains an array of Objectids (references to documents of books collection) as such:
var UserSchema = new Schema({
[...],
externalids: [{type: Schema.Types.ObjectId, ref: 'Books', required: false}]
}, {collection: 'myusers'});
At runtime, I'd like to constantly fill that array (externalids) with ids of new book documents. This is how I do it:
var newBook = new Book({ ... });
newBook.save(function (err){
if (err){
//whatever
}else{
User.update({ _id: req.user._id }, { $set: { externalids: newBook._id }}, function(err){
//whatever
});
}
});
Unfortunately, I can't use something like:
externalids: externalids.push(newBook._id)
I even tried:
User.update({ _id: req.user._id }, { $push: { externalids: newBook._id }}
But it wouldn't help either.
Thus, the array always only contains one value (the latest) and won't be filled up. Is there a quick way to append more values? Would be nice if there was a quicker way than reading the array content first, storing it to a local temporary array, append the new value and write the entire array back...
Cheers
Igor
Try $addToSet instead of $push to avoid duplicate id.
User.update({ _id: req.user._id }, { $addToSet : { externalids: newBook._id }}
What can be your issue is that you previously use $set to update an user. This will initially create externalids as string, not array, hence you cannot use $push/$addToSet on externalids afterwards. To correct that, try to update your user externalids as an array first:
User.update({ _id: req.user._id }, { $set : { externalids: [] }}