Mongoosejs can't query with findById - mongodb

I have a meteor application saving stuff to mongodb and I have an api I wish to make and expose via REST.
express = require 'express'
mongoose = require 'mongoose'
app = express()
mongoose.connect process.env.MONGO_URL
Account = mongoose.model 'users',
profile:
available: Boolean
app.get "/accounts/meta/:account_id", (req, res) ->
account = Account.findById req.params.account_id
, (error, account) ->
if account?
res.jsonp
account: account
else
res.jsonp 404,
error: "Account not found"
app.listen 2000
The problem is that I can't query by the id's I see in my database. For example I have this user:
{
"_id": "zcdsHuKr5dTh3xHz5",
"createdAt": 1373188729653,
"last_seen": 1373465529548,
"profile": {
....
If I go to /accounts/meta/zcdsHuKr5dTh3xHz5 it says 'Cast to ObjectId failed for value "zcdsHuKr5dTh3xHz5" at path "_id"'. I tried in every possible way to query for my document without luck. Any ideas?

The problem is that you need to define a schema for your model to tell Mongoose that your _id field is a String instead of the standard ObjectId in this collection:
AccountSchema = new mongoose.Schema
_id: String
profile:
available: Boolean
Account = mongoose.model 'users', AccountSchema

Seems that your _id field isn't an ObjectId. The method findById on Mongoose expects:
id objectid, or a value that can be casted to one
So, if your _id in fact isn't an ObjectId, you should query using findOne method
account = Account.findOne { "_id" : req.params.account_id }

The currently propagated answer is not a good idea. Don't change the schema for your model to tell Mongoose that your _id field is a String. That is a bad idea in terms of validation and should be considered a hack.
Try this instead:
If you want to query for an _id in mongoose, you have to cast the _id to ObjectId
AccountSchema = new mongoose.Schema({
_id: ObjectID(),
profile: {
available: Boolean
});
Account = mongoose.model('users', AccountSchema);
Mongoosejs requires you to cast the id in the query as well (I didn't find anything about this in the mongoose documentation either):
account = Account.findOne({ "_id" : mongoose.Types.ObjectId(req.params.account_id) });

Related

Argument passed in must be a single String of 12 bytes or a string of 24 hex characters, Mongoose ObjectId err

I actually searched a ton and I saw a ton of mentions of my problem here but none of the things I tried helped me fix the issue i'm having.
I have a Room Scheme that looks like this:
const ObjectId = mongoose.Schema.ObjectId;
const roomSchema = mongoose.Schema({
users: [{
type: ObjectId,
ref: 'User'
}],
messages: [{
type: ObjectId,
ref: 'Message',
}],
post: {
type: ObjectId,
ref: 'Post'
}
});
As you can see I have an array of users with ref to another schema Users
I'm trying to query all the Rooms that has a User ObjectId in it (search ObjectId in an array).
while I can easily get this with querying mongo from cmd using this:
db.users.find({users:ObjectId('THE_OBJECT_ID')});
when I try to get the same while using mongoose it fails with:
Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters
Here is how my route and find looks like:
app.route('/rooms/list/:user_id')
.get((req, res) => {
var query = { users: "USER_ID" };
Room.find(query ).populate('messages').then((data) => {
res.status(200).json(data);
}).catch((err) => {
console.log(err);
});
})
I tried to create type of object ID and use it but it still doesn't work.
var mongoose = require('mongoose'),
userId = 'THE_USER_ID';
var id = mongoose.Types.ObjectId(userId);
and than
Rooms.find({'users': id });
but it still doesn't work.
I also tried altering my query search using $in, $elemmatch it worked on cmd but failed when querying using mongoose.
Any help would be appreciated.
Issue :
If you check this :
var query = { users: "USER_ID" };
(Or)
userId = 'THE_USER_ID';
var id = mongoose.Types.ObjectId(userId);
What are you trying to do here ? You are passing in string USER_ID or THE_USER_ID as input and trying to convert it to type of ObjectId(). But string inside ObjectId() has certain restrictions which is why mongoose is failing to convert passed in string value to ObjectId() and getting error'd out.
Try this code :
Code :
const mongoose = require('mongoose');
app.route('/rooms/list/:user_id')
.get((req, res) => {
var query = { users: mongoose.Types.ObjectId(req.params.user_id) };
Room.find(query).populate('messages').then((data) => {
res.status(200).json(data);
}).catch((err) => {
console.log(err);
});
})
Your input should be value of user_id (Which will be string) - Convert it to ObjectId() and then query DB. So value of user_id should be a string that obeys ObjectId()'s restrictions, You can take string from one of existing doc's ObjectId() & test your get api.

How can I dynamically build a mongoose query that has an objectId?

I'm trying to dynamically build a mongoose query. The problem I'm having is that I can't figure out how to do this when the query contains an objectId.
I'm using mongoose 5.4.6.
My mongoose schema looks something like this:
stuff: String,
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
moreStuff: String,
});
I need to dynamically build my query, and one of the possible fields to query for is user. The fields to query for are sent to the server via a params object. When the field I'm querying for is stuff, then it's easy. I just do something like the following:
let query = {};
query.stuff = params.stuff;
this.model('MyModel').find(query)...
However, I can't figure out how to search for user, because params.user is just the string version of the mongo id, but it needs to be formatted as objectId("params.user") for the query to work. That is, I need something like:
query.user = objectId("params.stuff");
How can I get this to work?
I usually do like this.
const ObjectId = require('mongodb').ObjectID
const MyModel = require('../models/mymodel')
let query = MyModel.findOne()
query.where('_id').equals(new ObjectId(params.stuff))

mongo mongoose populate subdocument returns null

I am trying to use node & mongoose's populate method to kind of 'join' 2 collections on query. The following is my schema setup:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ShopSchema = new Schema({
ssss: { type: Schema.Types.ObjectId, required :true, ref: 'Stat' },
ratings: [RatingSchema]
});
var RatingSchema = new Schema({
stat: { type: Schema.Types.ObjectId, required :true, ref: 'Stat' }
}, {_id: false});
Also I have setup the Stat mongoose model so that the queries works without error (but the result is not what I expected).
I tried to perform the following queries:
ShopSchema.statics.load = function(id, cb) {
this.findOne({
_id: id
}).populate('ssss', '_id stat_id').exec(cb);
};
mongoose.model('Shop', ShopSchema);
This gives me the correct result and the ssss is correctly referenced.
The result is something like this .
"ssss":{"_id":"5406839ad5c5d9c5d47091f0","stat_id":1}
However, the following query gives me the wrong result.
ShopSchema.statics.load = function(id, cb) {
this.findOne({
_id: id
}).populate('ratings.stat', '_id stat_id').exec(cb);
};
mongoose.model('Shop', ShopSchema);
This gives me ratings.stat = null for all results. Could someone tell me what I did wrong? Thanks.
I just found the answer by trial and error.....
in the last example ShopSchema is declared before the RatingSchema. So I am guessing Mongoose doesn't know exactly what is happening inside RatingSchema and making the populate returns an error. So if you declare RatingSchema before the ShopSchema and the populate method is working like a charm..

mongodb update failes on express session

I am using passportjs for authentication. I am using mongodb to store express sessions. The document that gets saved contains 3 fields _id, session, expires.
When I try to update the document using mongoose it does not. It does however find the document but does not update.
Would there be any lock on the document? When I try to update from mongo console it does...
Please help.
here is my code:
var conditions = { '_id' : req.sessionID};
var update = { $set: { 'ip': '111.11.111.1112' }};
Sessions.update(conditions, update, function (err, res) {
if (err) return callback("FAILED");
return callback("SUCCESS");
});
This is my schema.....
var mongoose = require('mongoose');
// define the schema for our user model
var sessionsSchema = mongoose.Schema({
_id : String,
session : String,
ip : String,
expires : String
});
// create the model for users and expose it to our app
module.exports = mongoose.model('sessionsIP', sessionsSchema, 'sessionsIP');

Mongoose Db: How can I use a parameterized method in a Mongoose query?

var mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Group = new Schema({
name: { type: String, required: true },
members: [{ type: ObjectId, ref: 'User' }],
leader: { type: ObjectId, ref: 'User' },
// more fields to filter by
});
Group.method('role', function (user) {
if (this.leader === user) return "Leader";
else if (this.members.indexOf(user) >= 0) return "Member";
else return "Non-Member";
});
I'm a Mongoose newbie and my first real query was a tricky one. I need to select a set of groups an display group name and the role of the current user (user_id is stored in session variable).
Can I use the 'role' method in a Mongoose select query?
Perhaps I should use a custom Node stream and implement the role method there?
I'm note sure that my conditions (this.leader === user) or (this.members.indexOf(user) >= 0) are correct or efficient. I need to avoid loading the User object for every Group document.
Code example needed.
Thanks for your help!
what you want to use is the aggregation framework
http://docs.mongodb.org/manual/applications/aggregation/
You might need to dip down into the native driver for this query.