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}]
Related
So I have this Mongoose Schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var CommentSchema = new Schema({
body: {type: String, required: true, max: 2000},
created: { type: Date, default: Date.now },
flags: {type: Number, default: 0},
lastFlag: {type: Date, default: Date.now()},
imageBanned: {type: Boolean, default: false},
fileName: {type: String, default: ""}
}, {
writeConcern: {
w: 0,
j: false,
wtimeout: 200
}
});
var PostSchema = new Schema({
body: {type: String, required: true, max: 2000},
created: { type: Date, default: Date.now },
flags: {type: Number, default: 0},
lastFlag: {type: Date, default: Date.now()},
fileName: {type: String, default: ""},
imageBanned: {type: Boolean, default: false},
board: {type: String, default: ""},
comments: [{ type: Schema.Types.ObjectId, ref: 'Comment' }]
}, {
writeConcern: {
w: 0,
j: false,
wtimeout: 200
}
});
var Post = mongoose.model('Post', PostSchema);
var Comment = mongoose.model('Comment', CommentSchema)
module.exports = {Post, Comment}
And I'm trying to query a Comment inside the comment array in post.
This is the endpoint I'm trying:
router.post('/flagComment', (req, res, next)=>{
console.log('inside /flagComment')
console.log('value of req.body: ', req.body)
model.Post.findOne({"comments._id": req.body.id}).exec((err, doc)=>{
if(err){
console.log('there was an error: ', err)
}
console.log('the value of the found doc: ', doc)
res.json({dummy: 'dummy'})
})
})
However, this gives the following terminal output:
value of req.body: { id: '5c9bd902bda8d371d5c808dc' }
the value of the found doc: null
That's not correct...I've verified the ID is correct - why is the comment doc not being found?
EDIT:
I've attempted this solution (Can't find documents searching by ObjectId using Mongoose) by setting the objectID like this:
var ObjectId = require('mongoose').Types.ObjectId;
router.post('/flagComment', (req, res, next)=>{
console.log('inside /flagComment')
console.log('value of req.body: ', req.body)
console.log('value of objid req id : ', ObjectId(req.body.id))
model.Post.find({"comments._id": ObjectId(req.body.id)}).exec((err, doc)=>{
if(err){
console.log('there was an error: ', err)
}
console.log('the value of the found doc: ', doc)
res.json({dummy: 'dummy'})
})
})
And I get the following terminal output:
value of req.body: { id: '5c9bd902bda8d371d5c808dc' }
value of objid req id : 5c9bd902bda8d371d5c808dc
the value of the found doc: []
So, this is not yet a solution although it appears to be better than what I had.
You aren't querying for an ObjectId, no matter how much you think you are. You are querying for the ObjectId encoded as a hexidecial string, which is not the same thing. Properly typecast and you will likely have far more success.
Edited to elaborate, from a mongo (JS) REPL shell:
> // Omitting the _id, or generating a new one, are equivalent during insert.
> db.foo.insert({_id: ObjectId()})
WriteResult({ "nInserted" : 1 })
> db.foo.find() // As expected, we get back our _real_ ObjectId value.
{ "_id" : ObjectId("5c9cfab873724727778c0730") }
> // Can we "insert the record again" using a string version of the ID?
> db.foo.insert({_id: "5c9cfab873724727778c0730"})
WriteResult({ "nInserted" : 1 }) // Sure as heck can! No unique violation!
> db.foo.find() // Because THESE ARE NOT THE SAME
{ "_id" : ObjectId("5c9cfab873724727778c0730") }
{ "_id" : "5c9cfab873724727778c0730" }
After our IRC discussion, there seems to be difficulty in understanding the "searchable terms" in the answers you are being given. Search here on StackOverflow (or Google, or DDG) for "mongoose typecast ObjectId" (without quotes; or just "mongoose ObjectId"…) and you will find many answers, as this is a particularly common problem for Mongoose users.
Once try checking with populating the reference data first and then querying on the _id of the comment.
*Get the post id also from front end in addition to comment id, in that way it will be easier.
Post.findOne({_id:'postId'})
.populate({
path : 'comment',
match : { _id : 'commentId' }
})
.exec(...);
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 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 }
)
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.