Mongoose save model with object field - node.js

I'm trying to save a mongoose model that has a schema with an object field. When I try to save I get the error below. What am I missing?
I suspect this might have something to do with how mongoose objects are not quite like standard javascript objects since they are altered. However, what confounds me is that I'm doing exactly the same thing in another section of my code with a schema that has a nested object field and that works.
What I've tried:
To test, I changed my schema to list resulttype and resultround as individual fields without nesting and when I did that it worked.
I also tried creating an object with key value pairs outside of my model and then pass that object to my model. That did not work either.
Schema
var ResultSchema = new mongoose.Schema({
event_id : mongoose.Schema.ObjectId,
event_name: String,
event_type: String,
resultdate : String,
resulttype: {
type: String,
round: Number
},
// resulttype: String,
// resultround: Number,
});
Model save:
var newResult = new ResultModel({
// objNewResult
event_id: req.body.eventid,//hidden field
event_name: req.body.eventname, //hidden field
resultdate: req.body.resultdate,
// resulttype: resulttypelist,
// resultround: resultroundlist,
resulttype: {
type: req.body.resulttypelist,
round: req.body.resultroundlist
}
});
newResult.save(function (err, result) {
if (err) {
console.log("SOMETHING WENT WRONG");
console.log(err);
} else {
console.log("SUCCESSFUL RESULT ADDITION");
}
});
Error:
ValidationError: results validation failed: resulttype: Cast to String failed for value "{ type: 'standard', round: '1' }" at path "resulttype"

type is a reserved keyword in Mongoose schemas. It's used to specify the type of the field. When you specify this:
resulttype: {
type: String,
round: String
},
Mongoose will consider the field resulttype to be a String. So you have to use another name than type.

type is a reserved key:
By default, if you have an object with key 'type' in your schema, mongoose will interpret it as a type declaration. Source.
So right now, resulttype is expected to be of type String. You can use a different key instead:
Schema:
resulttype: {
resultType: String,
round: String
},
Model Save:
var newResult = new ResultModel({
// ...
resulttype: {
resultType: req.body.resulttypelist,
round: parseFloat(req.body.resultroundlist),
}
});

Related

Is Mongoose support Set data type?

I wanna store unique values of any type, whether primitive values or object references. is possible? For example:
const activity = mongoose.Schema({
participants : {
type: Set, // <-- is possible?
required: true,
},
// ...
}
No, as of now it supports following data types in the latest version[5.6.3].
String,
Number,
Date,
Buffer,
Boolean,
Mixed,
ObjectId,
Array,
Decimal128,
Map
For more info on mongoose schema, please refer here
For data types supported by mongoDB, refer here
You can also use the $addToSet operator while updating that field.
For example:
const likeBook = async (req, res) => {
const {id: bookID} = req.params
const authorId = req.user.userId
const book = await Book.findByIdAndUpdate({_id: bookID}, {
$addToSet: {
like : authorId
}
})
if (!book) {
return new NotFoundError(`No Book with id: ${bookID}`)
}
await book.save()
res.status(StatusCodes.OK).json({book})
}
This will only add authorId to like array of Book if that Id doesn't exist.
You can use a setter to create a set-like array:
const activity = mongoose.Schema({
participants : {
type: Schema.Types.Mixed, // Array would probably also work
required: true,
set: toSet
},
// ...
}
function toSet(a) {
return [...new Set(a)];
}

Nodejs Mongodb verify value on schema array

I would like to know how I can verify if a value is in an array of a different value in the schema. Have a look at this example:
const progressSchema = mongoose.Schema({
possible_statuses: {
type: Array
},
first_status: {
type: String
}
});
And a POST (insert) example of this would be:
{
possible_statuses: ['Untouched', 'In Progress', 'Complete'],
first_status: 'Untouched'
}
But a PUT (update) on the above item using this:
{
id: hwad0912he109sj(whatever),
first_status: 'Recalled'
}
Should throw an error like: Invalid first_status
Could someone please give me an example of how this would work. I would assume you would need to use something like progressSchema.pre('save'...
Mongoose has an enum property for this usecase. See the documentation and example below:
const progressSchema = mongoose.Schema({
possible_statuses: {
type: Array
},
first_status: {
type: String,
enum: ['Untouched', 'In Progress', 'Complete']
}
});

Mongoose findOneAndUpdate cast error with custom _id

I have my Person schema like this :
const schema = new mongoose.Schema({
_id: Number,
name: String,
birthday: Date,
sex: String
});
schema.pre('findOneAndUpdate', async function (next) {
try {
let counter = await Counters.findByIdAndUpdate('person',
{
$inc: {
value: 1
}
},
{ new: true}
);
this._update._id = counter.value;
next();
}
catch (err) {
next(err);
}
});
The problem is when I try to add some new persons with findOneAndUpdate and upsert: true, it generates a CastError: Cast to ObjectId failed for value "18" at path "person".
My _id is defined as a Number so I don't understand why it's trying to cast it to an ObjectId ?
Update :
I found my problem, the Person model is referenced in some other model but I forgot to change the ref type in the other model...
person: {
type: Number, //HERE
ref: 'person',
required: true
}
You can change the type of the_id property although ins't a good approach, but actually you can't change the value since it's immutable and represents the primary key of the document. Keep in mind that _id is very important for MongoDB life cycle, like indexing. If you aim to change an Entity key, you can create other property, something like person_id.
_id is an auto generated property for MongoDB. If you want to add try a different name for the Id attribute like "personId" or you can use the auto generated Id by MongoDB without creating a seperate Id.

Get fields set to unique in schema from Mongoose

I have a desire to check which fields in a schema are set to unique, similar to getting the indexes for a schema via MyCollection.collection.getIndexes(). Can this information be found somewhere on the schema object?
Try this:
var schema = new mongoose.Schema({
a: {
type: String,
unique: true
},
b: {
type: String
}
});
schema.tree.a.unique; // true
schema.tree.b.unique; // undefined
schema.path('a').options.unique; // true
schema.path('b').options.unique; // undefined

How can i use an if statement in a mongoose query?

i have a mongodb collection named Feed and it has an attribute named "type". according to that string, i want to send a changeable fields with json. For example if type is "photo" i want to do somethig like that
schema.find({number: "123456"},"body number",
function(err, data) {
but if the string is story, instead of photo; İn the same 'schema.find' query,it should create a json with "body url" instead of "body number". and they all should be passed with the same json.
res.json(data);
For a clear example, i want my json to be like this. as you se the fields change according to "type". but they are all actually in the same collection.
[
{
type: 'photo',
number: 123456,
url: 'asd.jpg',
},
{
type: 'story',
body: 'hello',
number: 123456,
}
]
So basically you want to return certain documents fields from the Feed collection, which are specified in a variable like e.g. "firstName pic points photos".
Are there Feed documents with the story field?
The Model.find() does not create any schema.
Maybe edit with further code so we can understand the command.
For document-specific JSON formatting like this, you can override the default toJSON method of your Feed model as shown in this gist.
UPDATE
If you want this sort of flexibility in your documents then it's even easier. Just define your schema to include all possible fields and then only set the fields that apply to given document for its type. The fields that you don't use won't appear in the document (or in the JSON response). So your schema would look like:
var feedSchema = new Schema({
type: { type: 'String' },
venue: Number,
url: String,
body: String
});
Take a look to mongoose-schema-extend. Using the 'Discriminator Key' feature, you can instruct .find() to create the proper model in each individual case.
Your code should look like this (not tested):
var feedSchema = new Schema({
venue: Number,
}, {discriminatorKey : 'type' }});
var photoSchema = feedSchema.extend({
url: String
});
var storySchema = feedSchema.extend({
body: String
});
var Feed= mongoose.model('feed', feedSchema );
var Photo= mongoose.model('photo', photoSchema );
var Story= mongoose.model('story', storySchema );
//'photo' and 'story' will be the values for 'type' key
Feed.find({venue: "123456"}, function(err, models) {
console.log(models[0] instanceof Photo); // true
console.log(models[0] instanceof Story); // false
console.log(models[1] instanceof Photo); // false
console.log(models[1] instanceof Story); // true
});

Resources