I'm trying to specify the schema of my db in mongoose. At the moment I do this:
var Schema = mongoose.Schema;
var today = new Date(2011, 11, 12, 0, 0, 0, 0);
var personSchema = new Schema({
_id : Number,
name: { type: String, required: true },
tel: { type: String, required: true },
email: { type: String, required: true },
newsitems: [{ type: Schema.Types.ObjectId, ref:'NewsItem'}]
});
var taskSchema = new Schema({
_id: Number,
description: { type: String, required: true },
startDate: { type: Date, required: true },
newsitems: [{ type: Schema.Types.ObjectId, ref:'NewsItem'}]
});
var newsSchema = new Schema({
_id: Number,
creator : { type: Schema.Types.ObjectId, ref: 'Person' },
task : { type: Schema.Types.ObjectId, ref: 'Task' },
date: { type: Date, required:true },
loc: {type: String, required: true }
});
var NewsItem = mongoose.model('NewsItem', newsSchema);
var Person = mongoose.model('Person', personSchema);
var Task = mongoose.model('Task', taskSchema);
var tony = new Person({_id:0, name: "Tony Stark", tel:"234234234", email:"tony#starkindustries.com" });
var firstTask = new Task({_id:0, description:"Get an interview with the president", startDate:today});
var newsItem1 = new NewsItem({_id:0, creator: tony.id, task: firstTask.id, date: today, loc: "NY"});
newsItem1.save(function (err) {
if (err) console.log(err);
firstTask.save(function (err) {
if (err) console.log(err);
});
tony.save(function (err) {
if (err) console.log(err);
});
});
NewsItem
.findOne({ loc: "NY" })
.populate('creator')
.populate('task')
.exec(function (err, newsitem) {
if (err) console.log(err)
console.log('The creator is %s', newsitem.creator.name);
})
I create the schemas and try to save some data.
The error:
{ message: 'Cast to ObjectId failed for value "0" at path "creator"',
name: 'CastError',
type: 'ObjectId',
value: '0',
path: 'creator' }
I wrote this code based on : http://mongoosejs.com/docs/populate.html#gsc.tab=0
The db I try to create looks like this: Specify schema in mongoose .
How can I fix this?
The example from the mongoose docs you referenced uses Number for the personSchema._id field, and ObjectId for the others.
I presume they do this in the example only to demonstrate that it's possible to use either. If you do not specify _id in the schema, ObjectId will be the default.
Here, all your records have an _id field which is an ObjectId, yet you're treating them like numbers. Furthermore, fields like personID and taskID do not exist, unless you've left out the part where you define them.
If you did want to use numbers for all your _id fields, you'd have to define that in the schemas.
var newsSchema = new Schema({
_id: Number,
_creator: {type: ObjectId, ref: "Person"},
// ...
})
var personSchema = new Schema({
_id: Number,
// ...
})
Then to create a news item with a particular ID, and assign it to a creator:
var tony = new Person({_id: 0});
var newsItem = new NewsItem({_id: 0, creator: tony.id});
However the thing to note here is that when you use something other than ObjectId as the _id field, you're taking on the responsibility of managing these values yourself. ObjectIds are autogenerated and require no extra management.
Edit: I also noticed that you're storing refs on both sides of your associations. This is totally valid and you may want to do it sometimes, but note that you'd have to take care of storing the references yourself in the pre hook.
I was receiving this error after creating a schema:
CastError: Cast to ObjectId failed for value “[object Object]” at path “_id”
Then modifying it and couldn't track it down. I deleted all the documents in the collection and I could add 1 object but not a second. I ended up deleting the collection in Mongo and that worked as Mongoose recreated the collection.
Related
This may seem like a vague question, but I'm going to try to explain the best I can. As a side note, I'm quite new to using mongoose :)
I have a mongoose-schema storing different values for each user, like so...
let userSchema = mongoose.Schema({
user: { type: String, required: true, unique: true },
pass: { type: String, required: true },
files: [{ type: String, required: false }],
});
The "files"-key contains an array of values, lets say for example:
userSchema.files = [value1, value2, value3]
And I want each value to be connected to some kind of ID, so that when I call the specified ID, I get the specified value. Just for demonstrating purposes, it could look something like this:
userSchema.files = [{value:value1, id: id1},
{value:value2, id: id2},
{value:value3, id: id3}]
Then I want to find the specified id, and return it's "value"-key in a request:
router.route("/home/:id")
.get(restrict, function(req, res) {
User.findOne({ user: req.session.Auth.username }, function(error, data) {
data.files.forEach(function(file) {
if (file.id === req.params.id) {
response.render("../home", file.value)
}
}
});
});
How can I do this? Tried pushing an object to files, but that didn't work as expected. Read something about ObjectId, but couldn't quite understand it. Any tips?
I think you simply need to create a separate model for File and connect it to your User model using the 'ref' keyword :
let fileSchema = mongoose.Schema({
_id : Number,
value : String
});
let userSchema = mongoose.Schema({
user: { type: String, required: true, unique: true },
pass: { type: String, required: true },
files: [{ type: Number, ref: 'File' }]
});
let User = mongoose.model('User', userSchema);
let File = mongoose.model('File', fileSchema);
let f1 = new File({ _id: 1, value: 'File 1'});
let f2 = new File({ _id: 2, value: 'File 2'});
let f3 = new File({ _id: 3, value: 'File 3'});
let user1 = new User({user:'chuck', pass:'norris'});
user1.files.push(f1);
user1.files.push(f2);
user1.files.push(f3);
user1.save(function(err){ });
Now to get the data back:
User
.findOne({ user: 'chuck' })
.populate('files') // only works if we pushed refs to children
.exec(function (err, user) {
if (err) return handleError(err);
console.log(user);
//you can now loop through user.files and compare _id
user.files.forEach(function(file) {
if (file._id === req.params.id) {
response.render("../home", file.value)
}
}
});
You can read about mongoose reference population here: http://mongoosejs.com/docs/populate.html
EDIT [SOLVED]:
I was connecting to the wrong database...
I changed
var dbURI = 'mongodb://localhost/wifiplz'
to
var dbURI = 'mongodb://localhost/wifiPlz'
so all of this was due to a typo (uncapitalized p). Anyone with this type of problem make sure you are connecting to the right database!
Here is my schema file (location.js):
var mongoose = require('mongoose');
var openingTimeSchema = new mongoose.Schema({
days: {type: String, required: true},
opening: String,
closing: String,
closed: {type: Boolean, required: true}
});
var reviewSchema = new mongoose.Schema({
author: String,
rating: {type: Number, min: 0, max: 5, required: true},
createdOn: {type: Date, default: Date.now},
reviewText: String
});
var locationSchema = new mongoose.Schema({
name: {type: String, required: true},
address: {type: String, required: true},
rating: {type: Number, default: 0, min: 0, max: 5},
facilities: [String],
coords: {type: [Number], index: '2dsphere'},
openingTimes: [openingTimeSchema],
reviews: [reviewSchema]
});
// compiling schema as 'Location' model
mongoose.model('Location', locationSchema);
In my routes, I map the route to appropriate controller:
router.get('/locations/:locationId', locationsCtrl.locationRead);
In my controller (locationsCtrl.js) I try to find a location by id:
var mongoose = require('mongoose');
var Location = mongoose.model('Location');
module.exports.locationRead = function(req, res) {
Location
.findById(req.params.locationId)
.exec(function(err, location) {
if (err) throw err;
res.status(200);
res.json(location); // returns null
});
}
When I tested this, I am always getting null for valid ids. Would appreciate some insight as to why. Thanks.
edit:
Checking for the name of the collection on my computer using mongo and show collections, I get locations as the collection name. This is as expected. Although specifying mongoose.model('Location', locationSchema, 'locations') doesn't have any effect.
Make following changes :
var mongoose = require('mongoose');
var Location = mongoose.model('Location');
module.exports.locationRead = function(req, res) {
Location
.findOne({_id: req.params.locationId}, function (err, location){
if (err) throw err;
res.status(200);
res.json(location); // returns null
});
}
_id could be your any field so replace your db field with _id but make sure that field should be primary in nature or unique. If it's not create an index over that field.
I have a question about the way I am using the "upsert" query on mongoose. For some reason for a particular model it does not insert a new model even when upsert is true. It also doesn't send out an error telling me why it didn't update. It just returns numAffected=0, here is my current method
query = {gatewayId:req.body.gatewayId};
body = {$push:{xbees:{$each: req.body.xbees}},
"$setOnInsert":{address:req.body.address}};
options = [{upsert:true},{runValidators:true}]
GatewayData.update(query,body,options,function(err,numAffected,rawResposne){
if (err) return next(err);
if(numAffected == 0){
console.log("ohno!");
}
});;
Here is a copy of the model for reference
var xbeeMapping = new mongoose.Schema({
...
});
var GatewayData = new mongoose.Schema({
address: {type: String, uppercase:true, required:true},
gatewayId: {type: String, match : validators.gateway_matcher, required: true},
timestamp: {type: Date, default: Date.now},
panID: {type: String, uppercase:true},
radThreshold: {type: Number, default:30},
roomThreshold: {type: Number, default:22.22},
radCritical: {type: Number, default:15},
roomCritical: {type: Number, default:19.5},
xbees:[xbeeMapping]
});
GatewayData.index({gatewayId:1});
module.exports = mongoose.model('GatewayData', GatewayData);
Note that this works properly when updating just not when inserting. Also im sorry if this is too wordy and please tell me if I should cut out my schema from the question.
Kevin B mentioned in the comments to turn on debugging.
I did and found the following:
Mongoose: gatewaydatas.update({
gatewayId: '00000000-00000000-00409DFF-FFFFFFFD' })
{ '$push':
{ xbees:
{ '$each':
[ { serialNumber: '40AC1233',
roomNumber: 'LR', xbeeAddress:
'NODE_[40:AC:12:33]!',
_id: ObjectId("55563d50f9c72ca75c15612c") } ] } },
'$setOnInsert': { address: 'Stephens' } } {} –
The options were not being read properly!!
The correct format for options is
options = {upsert:true, runValidators:true}
not
options = [{upsert:true},{runValidators:true}]
I have the following 2 schema's
question.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var questionsSchema = new Schema({
nr: Number,
points: Number,
description: String,
isActive: {type: Boolean, required: true, default: true}
});
module.exports = mongoose.model('Question', questionsSchema);
round.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var roundSchema = new Schema({
name: String,
index: Number,
questions: {type: [Schema.Types.ObjectId], ref: 'Question'},
createdOn: {type: Date, required: true, default: Date.now()},
isActive: {type: Boolean, required: true, default: true}
});
module.exports = mongoose.model('Round', roundSchema);
There is some data that gets filled correctly, however when I try even the most simple query, it won't even work:
var Round = require('../model/round.server.model.js');
function findAll(req, res) {
Round.find().populate('questions').exec(function (err, results) {
if (err) {
console.log("An error occured when receiving all rounds!", err);
return res.sendStatus(404);
}
console.log(results);
return res.send(results);
});
}
All rounds are retrieved, but the question arrays are empty, even the _id's themselves disappeared
I think it's because you initialize in the wrong way your population. I understand you want an array of questions in each of your round. Your error seems to be here.
questions: {type: [Schema.Types.ObjectId], ref: 'Question'}
You should do as following in order to make it work:
questions: [{type: Schema.Types.ObjectId, ref: 'Question'}]
Because actually, you're making an array of type and this doesn't mean anything.
I'm trying to dynamically create _id's for my Mongoose models by counting the documents in the db, and using that number to create the _id (assuming the first _id is 0). However, I can't get the _id to set from my values. Here's my code:
//Schemas
var Post = new mongoose.Schema({
//_id: Number,
title: String,
content: String,
tags: [ String ]
});
var count = 16;
//Models
var PostModel = mongoose.model( 'Post', Post );
app.post( '/', function( request, response ) {
var post = new PostModel({
_id: count,
title: request.body.title,
content: request.body.content,
tags: request.body.tags
});
post.save( function( err ) {
if( !err ) {
return console.log( 'Post saved');
} else {
console.log( err );
}
});
count++;
return response.send(post);
});
I've tried to set the _id a number of different ways, but it's not working for me. Here's the latest error:
{ message: 'Cast to ObjectId failed for value "16" at path "_id"',
name: 'CastError',
type: 'ObjectId',
value: 16,
path: '_id' }
If you know what's going on, please let me know.
You either need to declare the _id property as part of your schema (you commented it out), or use the _id option and set it to false (you're using the id option, which creates a virtual getter to cast _id to a string but still created an _id ObjectID property, hence the casting error you get).
So either this:
var Post = new mongoose.Schema({
_id: Number,
title: String,
content: String,
tags: [ String ]
});
Or this:
var Post = new mongoose.Schema({
title: String,
content: String,
tags: [ String ]
}, { _id: false });
The first piece of #robertklep's code doesn't work for me (mongoose 4), also need to disabled _id
var Post = new mongoose.Schema({
_id: Number,
title: String,
content: String,
tags: [ String ]
}, { _id: false });
and this works for me
Create custom _id in mongoose and save that id as a mongo _id.
Use mongo _id before saving documents like this.
const mongoose = require('mongoose');
const Post = new mongoose.Schema({
title: String,
content: String,
tags: [ String ]
}, { _id: false });
// request body to save
let post = new PostModel({
_id: new mongoose.Types.ObjectId().toHexString(), //5cd5308e695db945d3cc81a9
title: request.body.title,
content: request.body.content,
tags: request.body.tags
});
post.save();
This works for me when saving new data for the schema. I used the exact code below in my project
new User(
{
email: thePendingUser.email,
first_name: first_name || thePendingUser.first_name,
last_name: last_name || thePendingUser.last_name,
sdgUser: thePendingUser.sdgUser,
sdgStatus: "active",
createdAt: thePendingUser.createdAt,
_id: thePendingUser._id,
},
{ _id: thePendingUser._id }
)