Mongoose Find By Ref ID - node.js

so I have two schemas, User und Company
const UserSchema = new mongoose.Schema({
_createdAt: Date,
company: {type: mongoose.Schema.Types.ObjectId, ref: 'company'},
email: String,
});
const CompanySchema = new mongoose.Schema({
_createdAt: {
type: Date,
required: true
},
name: {
type: String,
required: true
}
});
const userModel = mongoose.model("user", UserSchema, "user");
const companyModel = mongoose.model("company", CompanySchema, "company");
I would now like to query for a specific User by his Company _id, but for some reason this is not working, it returns an empty array even though I have a user with the exact company ObjectId in my Database.
userModel.find({company: "5cfa4352ffc1c8135d8276a4"})
.exec((err, user) => {
console.log(user);
}
In my mongo shell the command
db.user.find({company: "5cfa4352ffc1c8135d8276a4"})
returns the users as expected so why does this not work in mongoose? Thanks in advance

Try this
const ObjectId = require('mongodb').ObjectID;
then
db.user.find({company: ObjectId("5cfa4352ffc1c8135d8276a4")})
I hope it will work

If you want to find by that id you probably need to do this:
const mongojs = require('mongojs');
const ObjectId = mongojs.ObjectId;
db.user.find({company: ObjectId("5cfa4352ffc1c8135d8276a4")})
Since you are using moongose, you can get the ObjectId like this:
const mongoose = require('mongoose');
const objectId = mongoose.Types.ObjectId('569ed8269353e9f4c51617aa')

Related

MongoDB updating child document does not affect the original document and vise versa

I'm using mongoose and have these schema:
var mongoose = require('mongoose');
mongoose.connect(/*...*/)
const usersSchema = new Schema({
email: String,
name: String
})
const ordersSchema = new Schema({
user: usersSchema, // <--- ref to usersSchema
createdOn: Date,
// ...
})
const UsersModel = mongoose.model('Users', usersSchema );
const OrdersModel = mongoose.model('Orders', ordersSchema );
The problem is when I insert an entity into Users collection and put that entity reference into the Orders.user field, It seems that Mongo does clone that object in the Orders collection.
// insert user:
var savedUser = await(new UsersModel({
_id: mongoose.Types.ObjectId(),
email: 'AAA#example.com'
})).save();
// insert order with user reference:
var savedOrder = await(new OrdersModel({
_id: mongoose.Types.ObjectId(),
createdOn: new Date(),
user: savedUser // <--- ref to users
})).save();
Now I modify the user document:
// update original user:
var userDocToModify = await UsersModel.findById(savedUser._id);
userDocToModify.email = "BBB#example.com";
await userDocToModify.save();
Assertion will fail in the below line:
var orderDoc = await OrdersModel.findById(savedOrder._id);
assert(orderDoc.user.email == userDocToModify.email, 'email not changed in the orderDoc.user.email!');
Actually what you are doing here, is not referencing userSchema. You are embedding that schema into orders schema. If you want to reference user you should do as below:
const ordersSchema = new Schema({
user: {type: mongoose.Schema.Types.ObjectId, ref: 'Users'}
createdOn: Date,
// ...
})
In this case you just store the user id in parent document.
Now if you want to get orders and the user within it, you can either use mongoose population or $lookup in mongoose aggregation.

findById in Mongoose on a subdocument

I am attempting a findById in Mongoose on a subdocument....[posts]
How do i findById one specific [post] inside user?
var postSchema = new mongoose.Schema({
title: String,
content: String
});
var userSchema = new mongoose.Schema({
email: String,
name: String,
posts: [postSchema]
});
You could use the dot notation something like this
unique_id = req.params.id
const uniquePost = User
.find({'posts._id':unique_id })
or if you hade a schema like this nesting
var userSchema = new mongoose.Schema({
email: String,
name: String,
posts: {
posts: postSchema
}
});
you coulld again use dot notation to find the deeply nested id
like so
const uniquePost = User
.find({'posts.posts._id':unique_id })

Multiple schema in a file not working

I have two schema in singel schema.js file
var mongoose = require('mongoose');
var user = new mongoose.Schema({
name: String,
add: String,
role: String
});
var Organizationn = new mongoose.Schema({
name: String,
add: String,
name:String
});
module.exports = {
user: user,
Organizationn: Organizationn
};
accessing it like
var models = require("../models/schema");
models.user.findOne()
it says findone is not a function
whereas If i use singel user in a file it is working.
I have gone through this link and did export like above
cant get data from database after multiple schema declared (mongoose + express + mongodb
but not working
any idea?
Thanks
With the help of #anthony I figure out the issue
I need to do the below
module.exports = {
user: mongoose.model('user', user),,
Organizationn: mongoose.model('Organizationn', Organizationn)
};
If you exports more than one file than you will have to import with curly braces { schema1 }
var mongoose = require('mongoose');
var user = new mongoose.Schema({
name: String,
add: String,
role: String
});
var organization = new mongoose.Schema({
name: String,
add: String,
name:String
});
const userSchema = mongoose.model('users', user),
const organizationSchema = mongoose.model('organizations', organization)
module.exports = { User: userSchema, Organization: organizationSchema }
and then import
var { User } = require("../models/schema");
var { Organization } = require("../models/schema");
User.findOne()
Organization.findOne()
Try to look at it in this abstract way:
A mongoose.Schema is basically just an object.
A mongoose.model is a class that you customize with your schema object.
In other words, mongoose.model has all the database functions attached to it, the schema by itself doesn't.

mongoose db populate doesn't seem to work

So this is how my models are:
groupModel.js
var Schema = mongoose.Schema;
var groupSchema = new Schema({
uuid: String,
users: [{type: Schema.Types.ObjectId, ref:'users'}]
});
var Groups = mongoose.model('groups', groupSchema);
module.exports = Groups;
userModel.js
var mongoose = require('mongoose')
var Schema = mongoose.Schema;
var userSchema = new Schema({
username: String,
password: String,
firstname: String,
lastname: String,
email: String,
emailVerified: Boolean
});
var Users = mongoose.model('users', userSchema);
module.exports = Users;
and this is the api I am hoping to get it to work:
/* GET /group/list/:id listing. */
router.get('/list/:id', function(req, res) {
Group.findOne({uuid :
req.params.id}).populate('Users').exec(function(err, group){
if(err) throw err;
console.log(group);
res.status(200).send(group);
});
});
this is the response I get back:
{"_id":"5aaf52b4165e97aae4a0b42c","uuid":"iyzIc","__v":0,"users":
["58f5acae4733ae5f64XXXXea","590a663c2a32ad28e0XXXX29"]}
For some reason I am not able to replace the id's with actual data for the users. I was hoping to get user related details instead of ids for the two users. Am I doing something wrong? I am trying to learn nodejs and was hoping some nodejs expert will be able to find my silly mistake.
EDITED:
changing .populate('Users') -> .populate('users') fixed the issue.
Users being capitalized in populate is the problem!

How to set ObjectId as a data type in mongoose

Using node.js, mongodb on mongoHQ and mongoose. I'm setting a schema for Categories. I would like to use the document ObjectId as my categoryId.
var mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Schema_Category = new Schema({
categoryId : ObjectId,
title : String,
sortIndex : String
});
I then run
var Category = mongoose.model('Schema_Category');
var category = new Category();
category.title = "Bicycles";
category.sortIndex = "3";
category.save(function(err) {
if (err) { throw err; }
console.log('saved');
mongoose.disconnect();
});
Notice that I don't provide a value for categoryId. I assumed mongoose will use the schema to generate it but the document has the usual "_id" and not "categoryId". What am I doing wrong?
Unlike traditional RBDMs, mongoDB doesn't allow you to define any random field as the primary key, the _id field MUST exist for all standard documents.
For this reason, it doesn't make sense to create a separate uuid field.
In mongoose, the ObjectId type is used not to create a new uuid, rather it is mostly used to reference other documents.
Here is an example:
var mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Schema_Product = new Schema({
categoryId : ObjectId, // a product references a category _id with type ObjectId
title : String,
price : Number
});
As you can see, it wouldn't make much sense to populate categoryId with a ObjectId.
However, if you do want a nicely named uuid field, mongoose provides virtual properties that allow you to proxy (reference) a field.
Check it out:
var mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Schema_Category = new Schema({
title : String,
sortIndex : String
});
Schema_Category.virtual('categoryId').get(function() {
return this._id;
});
So now, whenever you call category.categoryId, mongoose just returns the _id instead.
You can also create a "set" method so that you can set virtual properties, check out this link
for more info
I was looking for a different answer for the question title, so maybe other people will be too.
To set type as an ObjectId (so you may reference author as the author of book, for example), you may do like:
const Book = mongoose.model('Book', {
author: {
type: mongoose.Schema.Types.ObjectId, // here you set the author ID
// from the Author colection,
// so you can reference it
required: true
},
title: {
type: String,
required: true
}
});
My solution on using ObjectId
// usermodel.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const ObjectId = Schema.Types.ObjectId
let UserSchema = new Schema({
username: {
type: String
},
events: [{
type: ObjectId,
ref: 'Event' // Reference to some EventSchema
}]
})
UserSchema.set('autoIndex', true)
module.exports = mongoose.model('User', UserSchema)
Using mongoose's populate method
// controller.js
const mongoose = require('mongoose')
const User = require('./usermodel.js')
let query = User.findOne({ name: "Person" })
query.exec((err, user) => {
if (err) {
console.log(err)
}
user.events = events
// user.events is now an array of events
})
The solution provided by #dex worked for me. But I want to add something else that also worked for me: Use
let UserSchema = new Schema({
username: {
type: String
},
events: [{
type: ObjectId,
ref: 'Event' // Reference to some EventSchema
}]
})
if what you want to create is an Array reference. But if what you want is an Object reference, which is what I think you might be looking for anyway, remove the brackets from the value prop, like this:
let UserSchema = new Schema({
username: {
type: String
},
events: {
type: ObjectId,
ref: 'Event' // Reference to some EventSchema
}
})
Look at the 2 snippets well. In the second case, the value prop of key events does not have brackets over the object def.
You can directly define the ObjectId
var Schema = new mongoose.Schema({
categoryId : mongoose.Schema.Types.ObjectId,
title : String,
sortIndex : String
})
Note: You need to import the mongoose module
Another possible way is to transform your _id to something you like.
Here's an example with a Page-Document that I implemented for a project:
interface PageAttrs {
label: string
// ...
}
const pageSchema = new mongoose.Schema<PageDoc>(
{
label: {
type: String,
required: true
}
// ...
},
{
toJSON: {
transform(doc, ret) {
// modify ret directly
ret.id = ret._id
delete ret._id
}
}
}
)
pageSchema.statics.build = (attrs: PageAttrs) => {
return new Page({
label: attrs.label,
// ...
})
}
const Page = mongoose.model<PageDoc, PageModel>('Page', pageSchema)
Now you can directly access the property 'id', e.g. in a unit test like so:
it('implements optimistic concurrency', async () => {
const page = Page.build({
label: 'Root Page'
// ...
})
await page.save()
const firstInstance = await Page.findById(page.id)
const secondInstance = await Page.findById(page.id)
firstInstance!.set({ label: 'Main Page' })
secondInstance!.set({ label: 'Home Page' })
await firstInstance!.save()
try {
await secondInstance!.save()
} catch (err) {
console.error('Error:', err)
return
}
throw new Error('Should not reach this point')
})

Resources