Search by ObjectId in mongoose schema nodejs - node.js

I am using mongoose with nodejs . I have item schema and user schema given below.
var userSchema = new Schema({
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
items : [{ type: Schema.Types.ObjectId, ref: 'Item' }]
});
var itemSchema = new Schema({
name: { type: String, required: true },
_owner : { type: Schema.Types.ObjectId, ref: 'User' }
});
I am trying to find item by user id(_owner in item schema).
I have tried to find directly
var uid = req.decoded._id;
var item = Item.findOne({"_owner": uid});
console.log(item.name); // undefined
By searching similar I found that id needs to be in ObjectId object so I tried
var uid = new mongoose.Types.ObjectId(req.decoded._id);
var item = Item.findOne({"_owner": uid});
console.log(item.name); // undefined
In both the cases item.name is undefined .Note that I have rechecked the value of req.decoded._id(by printing) with the db so it not undefined and present in db.
Is there anything I am doing wrong?

Model.findOne is an async call. It doesn't return the doc, it passes it to a callback function that you need to provide as a second parameter.
var uid = req.decoded._id;
var item = Item.findOne({"_owner": uid}, function(err, item) {
console.log(item.name);
});

Related

How to access and populate a referenced object schema in a larger document (MERN)

Making an app with a variety of schemas, many having other objects (Schema.Types.ObjectIds) as their properties.
When doing this, I can access the sub-object's property, as long as that sub-object's property is a string. But I'm having issues with it if that sub-object's property is yet another object (and then I need to query properties from that, string or not). For example, the first works fine:
user schema-> friends property of user (which is a list of user objects) -> username property of friend (which is a string)
But this I'm having issues with, I'm getting a string id and not the actual object**:
user schema-> profilePosts property of user (which is a list of profilePost objects) -> author property of profilePost (which is a user object)** -> author username property of profilePost (which is a string)
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var UserSchema = new Schema({
username: {type: String, required: true},
password: {type: String, required: true},
friends: [{type: Schema.Types.ObjectId, ref: "User"}],
profilePosts: [{type: Schema.Types.ObjectId, ref: "ProfilePost"}],
friendRequests: [{type: Schema.Types.ObjectId, ref: "User"}],
})
module.exports = mongoose.model('User', UserSchema);
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var ProfilePostSchema = new Schema({
date: {type: Date, required: true},
author: {type: Schema.Types.ObjectId, ref: "User"},
content: {type: String, required: true},
comments: [{type: Schema.Types.ObjectId, ref: "ProfilePostComment"}],
likes: [{type: Schema.Types.ObjectId, ref: "User"}],
hostProfile: {type: Schema.Types.ObjectId, required: true,ref: "User"},
})
module.exports = mongoose.model('ProfilePost', ProfilePostSchema);
exports.user_friends_render = async (req,res) => {
try {
const ViewedProfile = await User.find({}, 'username friends profilePosts friendRequests').populate('friends').populate('profilePosts').populate('friendRequests');
res.status(200).json(ViewedProfile);
} catch(error) {
res.status(200).json({message: error.message});
}
}
objects are string ids instead of objects
Mongoonse populate root object but not implicit deep populate
You can replace string by object as argument at populate method,
for provide full path to populate
const ViewedProfile = await User
.find({}, 'username friends profilePosts friendRequests')
.populate('friends')
.populate({
path: "profilePosts",
populate: [
{
path: "author",
// model: UserModel
},
{
path: "comments",
// model: ProfilePostCommentModel
},
{
path: "likes",
// model: UserModel
},
{
path: "hostProfile",
// model: UserModel
}
]
})
.populate('friendRequests');
You can see fully post at this problem.

MongoDB populate returning null

I am trying to populate my user schema with items but for some reason it does not populate anything in to the user schema. Could someone please take a look. I have 1 user and 1 item belonging to that user within my database but nothing is populating and I keep seeing null.
User Schema
var mongoose = require('mongoose')
var userSchema = mongoose.Schema({
name: {
type: String,
required: true
},
discordID: {
type: String,
required: true
},
discordImage: {
type: String,
required: true
},
items: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Item'
}]
})
const User = module.exports = mongoose.model('User', userSchema)
Item Schema
var mongoose = require("mongoose")
var itemSchema = mongoose.Schema({
name: {
type: String,
required: true
},
purchasedPrice: {
type: Number,
required: true
},
purchasedDate: {
type: String,
required: true
},
author: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "User"
}
})
const Item = module.exports = mongoose.model("Item", itemSchema)
Populate Code
app.get("/inventory", async (req, res) => {
try {
await req.user.populate({
path: 'items'
}).execPopulate()
console.log(req.user)
} catch (error) {
console.log(error)
}
res.status(200).render("inventory.ejs", { currentUser: req.user })
})
Objects in the DB:
Item:
User:
Used virtual method on user schema to create association
userSchema.virtual("items", {
ref: "Item",
localField: "_id",
foreignField: "author"
})
Worked fine with original code
I keep seeing null.
and
no its just empty
hints there are no items added to your user. You need to have some ids you can populate.
All populate does is convert an ObjectID into a document. There is no magic that will sync itemSchema.author with userSchema.items.
Hence, it's not enough to add the author to the item. You also need to add the item to the author.
So for example, you could add an item like this:
const item = new Item({author: user._id});
await item.save();
req.user.items.push( item );
await req.user.save();
Now when you log req.user, are there any items there?
Once you see objectIds, then you can go back and add that .populate('items') into the mix and I promise you it'll work.

Mongoose only saves array of object _id value

I'm trying to post the messages array to mongoose database, but it only saves the _id property instead the content and sender property too. What am I doing wrong?
Group Schema:
var GroupSchema = new mongoose.Schema({
name: {
type: String,
required: true,
minlenght: 1,
trim: true
},
messages: {
type: [{type: Schema.ObjectId, ref: 'Message'}]
},
_creator: {
type: mongoose.Schema.Types.ObjectId,
required: true
}
});
Message Schema:
var MessageSchema = new mongoose.Schema({
content: {
type: String,
required: true,
minlenght: 1,
trim: true
},
sender: {
type: String,
required: true
}
});
POST /rooms route without saving
const messages = [];
for (const m of req.body.messages) {
messages.push(new Message(m));
}
var group = new Group({
name: req.body.name,
_creator: req.user._id,
messages: messages
});
JSON data in postman
When I run GET I only get back the messages objectID values
This is by design. You have a cross-reference between your GroupSchema and your MessageSchema via:
messages: {
type: [{type: Schema.ObjectId, ref: 'Message'}]
}
What this means is that GroupSchema/messages would only contain the ObjectIds of the messages cross referenced with your Messages collection.
You need to use populate to get the actual documents loaded.
The ref option is what tells Mongoose which model to use during
population.

Field with ref as parameter in find doesn't work

I've got these two Schemas:
const BookSchema = new Schema({
name: { type: String, required: true },
author: [{ type: String }],
category: [{ type: String }],
store: { type:mongoose.Schema.Types.ObjectId, ref: 'Store'}
});
module.exports = mongoose.model('Book', BookSchema);
const storeSchema = new Schema({
name: { type: String, required: true },
slug: { type: String, index: true, required: true, unique: true}
});
module.exports = mongoose.model('Store', StoreSchema);
i'm trying to get the Books from a Store, described as follows:
exports.getBooksFromStore = async(idStore) => {
const data = await Book.find({store : idStore});
return data;
}
But, the find() written that way doesn't work.
The issue appears to be the expectation for the find method to return a promise object when it actually returns a query object. In the exampled code provided, the value assigned to data is the query object returned from the find method and not the intended promise object from the execution of the query.
To execute the query and return the promise object for it, the query exec method will need to be called.
exports.getBooksFromStore = async (idStore) => {
// const data = await Book.find({store : idStore});
const data = await Book.find({store : idStore}).exec();
return data;
};

mongoose populate as an instance object

When using mongoose's populate, you can get the document back but it is not an object instance where your schema methods are defined.
var tweetSchema = new mongoose.Schema({
owner: { type: Schema.Types.ObjectId, ref: 'User' },
message: { type: String },
});
var userSchema = new mongoose.Schema({
email: { type: String, unique: true, lowercase: true },
});
userSchema.methods.test = function(){
return 'test'
}
Tweet.findOne({}).populate('user').exec(function(err,tweet){
console.log(tweet.user.test);
});
This will result in an error 'Cannot read property 'userTwit' of undefined' as tweet.user is just a hash and not a document instance. Is there a way to make population return the document instance???
What would be a nice way to make something like this possible?
Unless you use lean(), the populated fields are doc instances.
Looks like your User field in tweetSchema is called owner, not user, so this should work:
Tweet.findOne({}).populate('owner').exec(function(err, tweet){
console.log(tweet.owner.test());
});

Resources