Mongo populate in optional field giving cast error - javascript

I have a 'vendor' and 'media' collection, media collection store vendor profile images and that is not mandatory field for vendors. Some vendors have profile picture some not, I want to list all vendors including their profile pictures reference. But I'm getting cast error when I populate profilePicture from meidas. I have other populate like 'userId', 'venueId' those are mandatory fields and it works.
Error:
CastError: Cast to ObjectId failed for value "xyz" at path "_id" for model "medias" undefined
Find Query:
const result = await resultObject.skip(skip)
.populate('userId')
.populate('venueId')
.populate('profilePicture')
.limit(parseInt(obj.pageSize, 10))
.sort({ [obj.sortColumn]: parseInt(obj.sortValue, 10) });
return result;
medias model
const MediasModel = () => {
const MediasSchema = new mongoose.Schema({
url: { type: String, required: true },
key: { type: String},
}, { timestamps: { createdAt: 'createdDate', updatedAt: 'modifedDate' } });
return mongoose.model('medias', MediasSchema);
};
module.exports = MediasModel();
vendors model
const Vendors = new mongoose.Schema({
venueId: { type: mongoose.Schema.Types.ObjectId, ref: 'venues' },
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'users' },
name: { type: String, required: true },
profilePicture: { type: mongoose.Schema.Types.ObjectId, ref: 'medias' },
}, { timestamps: { createdAt: 'createdDate', updatedAt: 'modifedDate' } });
module.exports = mongoose.model('vendors', Vendors);

Try the below code
const Vendors = require('path/to/model_vendor');
Vendors.find()
.populate([{path: 'venues'}, {path: 'users'}, {path: 'medias'}])
.skip(skip_value)
.limit(limit_value)
.sort({condition: 1 }) // Modify according to your need
.exec().
.then(vendors=>{
console.log(vendors)
}).catch(err=>{
console.log(err)
})

Related

MongoDB/GraphQL: Model.find() to get posts that userId is in likes

in my resolvers I have a method to find user likes with
async function userBookmarks(args, context) {
const user = checkAuth(context);
const posts = await Post.find({likes: {userId: user.id}})
return posts; }
But GraphQL returns an empty array.
For reference, the Post model is
likes: [
{
userId: String,
createdAt: String
}],
I came across a similar problem and fixed it by defining the MongoDB Collection name in the bottom of my MongoDB Schema.
const UserSchema = new mongoose.Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
location: {
type: String,
required: false
}
}, { collection : 'Users' });
EDIT:
Use $elemMatch to query several fields.
const posts = await User.find({likes: {$elemMatch: {userId: user.id}}})

MongoDB - how do I deep populate, an already populated field that has a reference to the schema it is in?

So I am having the following problem, I have a comments schema, which has a field called Replies and it is pointing toward the comment schema. The problem is that whenever I try to populate the following schema, everything except for the replies gets populated. Why is that happening, how do I fix it?
Comment Schema:
const {Schema, model} = require('mongoose')
const { ObjectId } = require('mongodb');
const commentSchema = new Schema({
Author:
{
type: ObjectId,
required: true,
ref: 'user'
},
Content:
{
type: String,
required: true
},
Likes:{
type: [ObjectId],
ref: 'user'
},
Replies: [this]
})
let comment = model('comment', commentSchema)
module.exports = comment
And that is how I populate the posts model:
let allPosts = await postModel
.find({})
.populate('Author Comments')
.populate(
(
{
path: 'Comments',
populate:[
{path: 'Author'}
]
},
{
path: 'Comments.Replies',
populate:[
{path: 'Author'}
]
}
)
)
and this is my post model, referenced in the previous code sample:
const {Schema, model} = require('mongoose')
const { ObjectId } = require('mongodb');
const postSchema = new Schema({
Author:
{
type: ObjectId,
required: true,
ref: 'user'
},
Content:
{
type: String,
required: true
},
Shares:{
type: [ObjectId],
ref: 'post'
},
Likes:{
type: [ObjectId],
ref: 'user'
},
Comments:{
type: [ObjectId],
ref: 'comment'
}
})
let post = model('post', postSchema)
module.exports = post

How do you save certain items for specific users in mongodb?

I'm working on a job tracker app.
User creates an account, saving the user in a mongodb collection.
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
});
const JobSchema = new mongoose.Schema({
position: {
type: String,
required: true
},
company: {
type: String,
required: true
},
status: {
type: String,
default: "applied"
},
date: {
type: Date,
default: Date.now
}
});
When a user adds a job, how would you store (.post) and retrieve (.get) that data to correspond to that specific user only?
Is there a way to save the users "_id" to the jobs added, and searchById to get the jobs?
It depends what exactly you want to achieve meaning what type of relationships your models will have. Lets say your users will have multiple jobs the best approach would be to store an array of ObjectIds. The refoption tells mongoose which collections to search during population of the array
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
jobs: [{type:Schema.Types.ObjecId,ref: 'Job'}]
});
and then when you query the database you chain populate('jobs') after the query.
You can read more on the subject here
For example,
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
});
const User = mongoose.model('User', UserSchema);
async function updateUser() {
let user = await User.findOne({"name": "a-unique-user-name-in-the-db"})
let userId = user._id
let newEmail = "asdf#asdf.com"
let updated = await User.updateOne(
{ "_id": userId },
{
$set: {
"email": newEmail,
}
}
)
if (updated) {
console.log("updated")
}
}
updateUser();

How can I limit the returned items from a Mongoose array populate?

I have a model that we use for a conversational chat, that uses nested arrays. Each time a user sends a message, it gets pushed into the messages array. This is my model:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ConversationSchema = new Schema({
sender: {
type: Schema.Types.ObjectId,
ref: 'User'
},
messages: [
{
message: String,
meta: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
delivered: Boolean,
read: Boolean
}
]
}
],
is_group_message: { type: Boolean, default: false },
participants: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
delivered: Boolean,
read: Boolean,
last_seen: Date
}
]
}, { timestamps: true });
module.exports = mongoose.model('Conversation', ConversationSchema);
I'm trying to find all conversations, that a user is a part of, but I'm unable to return only the most recent chat message, and it seems to ignore the options. Is this a model or populate issue on my end?
Conversation.find({ 'participants.user': { $all: [req.user._id] } })
.sort('-createdAt')
.populate({
path: 'sender',
select: '-_id -password -email -lastLogin -createdAt -updatedAt -__v',
})
.populate({
path: 'messages.meta.user',
select: 'username avatar',
options: {
limit: 1
}
})
.populate({
path: 'participants',
path: 'participants.user',
select: 'username avatar'
})
.then(conversation => {
if (!conversation) {
errors.noconversation = 'No conversation could be found';
return res.status(404).json(errors);
}
res.json(conversation)
})
.catch(err => res.status(404).json({ conversation: 'There are no conversations or an error occurred' }));

Can't POST to nested array with express js

It's my first post here so please let me know if there's anything incomplete about my question, or if there's anything else that is missing :)
I'm trying to make a POST request to an array in my data structure called features:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CategorySchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
categoryname: {
type: String,
required: true
},
items: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
itemname: {
type: String,
required: true
},
features: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
firstfeature: {
type: String
},
date: {
type: Date,
default: Date.now
}
},
{
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
secondfeature: {
type: String
},
date: {
type: Date,
default: Date.now
}
}
],
date: {
type: Date,
default: Date.now
}
}
],
date: {
type: Date,
default: Date.now
}
});
module.exports = Category = mongoose.model('category', CategorySchema);
I don't have any issues with posting to the items array with the following code:
router.post(
'/item/:id',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const { errors, isValid } = validateItemInput(req.body);
// Check Validation
if (!isValid) {
// if any errors, send 400 with erros object
return res.status(400).json(errors);
}
Category.findById(req.params.id)
.then(category => {
const newItem = {
itemname: req.body.itemname,
user: req.user.id
};
// Add to item array
category.items.unshift(newItem);
// Save
category.save().then(category => res.json(category));
})
.catch(err =>
res.status(404).json({ categorynotfound: 'No category found' })
);
}
);
But I can't figure out what I need to change here in order to add data to the features array:
router.post(
'/feature/:id/:item_id',
passport.authenticate('jwt', { session: false }),
(req, res) => {
Category.findById(req.params.id)
.then(category => {
const newFeature = {
firstfeature: req.body.firstfeature,
secondfeature: req.body.secondfeature,
user: req.user.id
};
// Add to item array
category.items.features.unshift(newFeature);
// Save
category.save().then(category => res.json(category));
})
.catch(err => res.status(404).json({ itemnotfound: 'Item not found'
}));
}
);
Issue solved with the following data structure:
features: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
price: {
type: String
},
size: {
type: String
},
date: {
type: Date,
default: Date.now
}
}
]
And then simply make a post request for one feature at a time.

Categories

Resources