mongoose 'findById' returns null with valid id - javascript

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.

Related

Mongodb Can't Query SubDocument by ID (returns null)

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(...);

mongoose upsert silently failling

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}]

Simple mongoose populate doesn't seem to be working

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.

Relating Mongodb Subdocuments

I'm building a REST api in node and i'm stuck on trying to include subdocuments into my GET requests. For example, I have two schema's right now, People and Locations. A location can have many people, and a person can have one location. So when you return /people I would like my location entry to contain the location information.
I believe my problem could be one of two things. I'm fairly new to node, so i'm not 100% sure if my schema's can see each other, when I try the common methods around the web, my location field get's populated with null. How I understand it, I store the location id in my people schema and then using subdocuments it will find the location with that id and fill in the info.
I also am not 100% sure how to use the populate function, and how exactly I should go about writing the response to my GET call. My code below, I'd love to hear what you have to say!
app.js
// Node Setup
var application_root = __dirname,
express = require('express'),
path = require('path'),
mongoose = require('mongoose'),
http = require('http');
var app = express();
// MongoDB Connection
var dbLocalhost = mongoose.createConnection('mongodb://localhost/lantern/');
// Configure Node
app.configure(function(){
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(application_root, "public")));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
app.port = 3000;
});
// Routes
var Locations = require('./routes/locations')(app, { 'mongoose': mongoose, 'db': dbLocalhost });
var People = require('./routes/people')(app, { 'mongoose': mongoose, 'db': dbLocalhost });
// Start the server
app.listen(app.port);
routes/people.js - has all the endpoints, but we're just concerned with GET for now
module.exports = function (app, options) {
var mongoose = options.mongoose;
var Schema = options.mongoose.Schema;
var db = options.db;
var PeopleModel = require('../schemas/peopleSchema')(db);
app.get('/people', function (req, res) {
return PeopleModel.find(function (err, obj) {
if (!err) {
return res.send(obj);
} else {
return res.send(err);
}
});
});
};
schemas/peopleSchema.js (the "location" field is what i want to populate)
module.exports = function(db) {
return db.model('People', PeopleSchema());
}
function PeopleSchema () {
var Schema = require('mongoose').Schema;
return new Schema({
first_name: String,
last_name: String,
address: {
unit: Number,
address: String,
zipcode: String,
city: String,
region: String,
country: String
},
image: String,
job_title: String,
created_at: { type: Date, default: Date.now },
active_until: { type: Date, default: null },
hourly_wage: Number,
location: [{type: Schema.ObjectId , ref: 'Locations'}], // Inheirit store info
employee_number: Number
}, { collection: 'people' });
}
schemas/locationsSchema.js - and the locations schema just incase
module.exports = function(db) {
return db.model('Locations', LocationsSchema());
}
function LocationsSchema () {
var Schema = require('mongoose').Schema;
return new Schema({
title: String,
address: {
unit: Number,
address: String,
zipcode: String,
city: String,
region: String,
country: String
},
current_manager: String, // Inherit person details
alternate_contact: String, // Inherit person details
hours: {
sunday: String,
monday: String,
tuesday: String,
wednesday: String,
thursday: String,
friday: String,
saturday: String,
holidays: String
},
employees: "", // mixin employees that work at this location
created_at: { type: Date, default: Date.now },
active_until: { type: Date, default: null }
}, { collection: 'locations' });
}

Mongoose: Cast to ObjectId failed for value

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.

Categories