Nodejs aggregate lookup returns empty array - javascript

I have user model
const mongoose = require("mongoose");
const uniqueValidator = require("mongoose-unique-validator");
const userSchema = mongoose.Schema({
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
isEmailVerified: { type: Boolean },
registrationStep: { type: Number, enum: [0,1,2,3]},
regDate: { type: Date },
companyName: { type: String },
oib: { type: String },
telephone: { type: String },
address: { type: String },
city: { type: String },
countryCode: { type: String },
postalCode: { type: String },
userType: { type: String, enum:['firms','drivers','both']},
approved: { type: Boolean },
isAdmin: { type: Boolean }
});
userSchema.plugin(uniqueValidator);
module.exports = mongoose.model("User", userSchema);
and documents model
const mongoose = require("mongoose");
const docsSchema = mongoose.Schema({
docsPath: { type: String, required: true },
creator: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true },
docType: { type: String, enum:['isr','lmp','pocmr'], required: true }
});
module.exports = mongoose.model("Docs", docsSchema);
I want to join collections so that for every user exists the user_docs field with docs data as in code below. I'm trying to do that with joining _id with creator as it is defined when creating a document
exports.getUsersAndDocs = (req, res, next) => {
const query = User.aggregate([
{
$lookup: {
from: "Docs",
localField: "_id",
foreignField: "creator",
as: "user_docs"
}
}]);
query
.then(fetchedUsers => {
res.status(200).json({
message: "Users fetched successfully!",
users: fetchedUsers,
});
})
.catch(error => {
res.status(500).json({
message: "Fetching users failed!"
});
});
};
I'm recieveing empty user_docs array. Thank you for your help

If someone has the same problem. I solved it by changing
from: "Docs"
to
from: Docs.collection.name

Related

How to find and populate reference object fields in a mongoose schema

I'm trying to fetch data from below mongoose schema, But I'm not sure how to fetch the role field, which is a type of RoleObject.
import * as mongoose from 'mongoose';
const Schema = mongoose.Schema;
const RoleObject = {
current_role: {
type: Schema.Types.ObjectId,
ref: 'Role',
autopopulate: true
},
new_role: {
type: Schema.Types.ObjectId,
ref: 'Role',
autopopulate: true
}
}
const UserRequestSchema = new mongoose.Schema({
group: {
type: Schema.Types.ObjectId,
ref: 'Group',
autopopulate: true,
required: true
},
user: {
type: Schema.Types.ObjectId,
ref: 'User',
autopopulate: true,
required: true
},
role: {
type: RoleObject
},
status: {
type: String,
required: true,
enum: ['pending', 'approved', 'denied']
},
type: {
type: String,
required: true,
enum: ['group-join', 'role-change']
},
active: {
type: Boolean,
required: true
}
});
UserRequestSchema.index( { group: 1, user: 1 }, { unique: true } );
export { UserRequestSchema };
Here I want populate the role field from the UserRequestSchema, which is given as RoleObject.
Is it possible through populate the field using find method or do I need to use aggregation ?
Try this
UserRequest.find({active:true}).populate({
path: 'role.current_role role.new_role',
model: 'Role',
select: 'name'
}).exec((error, result) => {
if (error) {
console.log(error, " ERROR")
}
console.log(result, "Result")
});
If you face any issue. Please let me know

Mongo DB - MissingSchemaError

I am working with mongo DB and mongoose and I'm getting the following error when running the code below.
"MissingSchemaError: Schema hasn't been registered for model "Project".\nUse mongoose.model(name, schema)"
import {...}
const { school } = request.params;
const document = await Document.find({
}).populate('project').lean();
if (document.project.school != school)
throw HTTP.forbidden('ERROR.DOCUMENT_DOES_NOT_BELONG_TO_YOUR_SCHOOL');
My schemas look as follows
const Document = new Schema({
name: { type: String },
type: { type: String },
project: {
type: Schema.Types.ObjectId,
ref: 'Project'
}
}, {
timestamps: true
});
const Project = new Schema({
name: { type: String },
school: {
type: Schema.Types.ObjectId,
ref: 'School'
}
}, {
timestamps: true
});
const School = new Schema({
name: { type: String },
curriculum: [{
type: Schema.Types.ObjectId,
ref: 'Curriculum'
}],
}, {
timestamps: true
});
Does anyone know what I need to do to overcome this everything has been initialised by the time this section of code is getting called?
Assuming you have created model for each schema, try writing your refs using lowercase:
const Document = new Schema({
name: { type: String },
type: { type: String },
project: {
type: Schema.Types.ObjectId,
ref: 'project'
}
}, {
timestamps: true
});
const Project = new Schema({
name: { type: String },
school: {
type: Schema.Types.ObjectId,
ref: 'school'
}
}, {
timestamps: true
});
const School = new Schema({
name: { type: String },
curriculum: [{
type: Schema.Types.ObjectId,
ref: 'curriculum'
}],
}, {
timestamps: true
});

Looping Over And Array of Objects and Updating Each One

I'm trying to update objects inside an array based on specific conditions that I check using two functions. I couldn't achieve this with the match feature available in mongoose.
As you can see below, I'm trying to loop over the array of posts, send each post and check if it fulfills a condition, then update it using findOneAndUpdate. The functions isLessThanOne and isAchieved return the expected value.
(async () => {
let posts = await Post.find()
posts.map(async (post) => {
if (isLessThanOneDay(post.deadline)) {
console.log(post.id, post._id)
await Post.findOneAndUpdate(post.id, { $set: { category: 'deadline' }})
} else if (isAchieved(post.milestones)) {
await Post.findOneAndUpdate(post.id, { $set: { category: 'achieved' }})
} else {
await Post.findOneAndUpdate(post.id, { $set: { category: 'newGoals' }})
}
})
})()
This is the schema
const { type } = require("express/lib/response")
const mongoose = require("mongoose")
const PostSchema = new mongoose.Schema({
// we have to link or refer each post to a user
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
},
title: {
type: String,
required: true
},
desc: {
type: String
},
milestones: [],
likes: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user"
},
fName: {
type: String,
required: true
},
date: {
type: String,
required: true
}
}
],
comments: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user"
},
text: {
type: String,
required: true
},
fName: {
type: String,
},
date: {
type: String,
}
}
],
rewards: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user"
},
fName: {
type: String,
required: true
},
date: {
type: String,
required: true
},
reward: {
type: String,
required: true
},
price: {
type: Number,
required: true
}
}
],
date: {
type: String,
required: true
},
shares: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user"
},
fName: {
type: String,
required: true
},
date: {
type: String,
required: true
}
}
],
deadline: {
type: String,
required: true
},
category: {
type: String,
}
})
module.exports = Post = mongoose.model('post', PostSchema)
The problem is that I couldn't update the posts and I've already tried using udpate, directly updating it with post.category then save. Any help would appreciated.
Try this:
(async () => {
let posts = await Post.find()
posts.map(async (post) => {
if (isLessThanOneDay(post.deadline)) {
console.log(post.id, post._id)
await Post.findOneAndUpdate({ _id: post.id }, { $set: { category: 'deadline' }})
} else if (isAchieved(post.milestones)) {
await Post.findOneAndUpdate({ _id: post.id }, { $set: { category: 'achieved' }})
} else {
await Post.findOneAndUpdate({ _id: post.id }, { $set: { category: 'newGoals' }})
}
})
})()
If I recall, the filter parameter must be an object.

Mongoose querying an array of objects

How to querying an array using Mongoose ?
search Schema:
const searchschema = new schema({
yeardate: { type: Number, required: true, min: 1820 },
word: { type: String, required: true, index: true },
user: [{ type: schema.Types.ObjectId, ref: 'User' }] })
user Schema:
const userschema = new schema({
username: { type: String, required: true, unique: true, index: true },//
name: { type: String, default: 'NoName' },
gender: { type: String, default: 'male' }, })
This is the query I have tried but did not work:
searchmodel.paginate({ 'user': { $elemMatch: { gender: 'female' } } }, { page: page, limit: 5, populate: ['user'] }).then(searches => {
if (!searches) {
return res.json({ message: 'there is no search' })
}else {
return res.json(searches)
}
})

findByIdAndUpdate keeps being caught in .catch

So when I am executing my findByIdAndUpdate it doesn't execute my promise as expected and goes into my catch. I sent responses to postman and using res.json(req.user.id) and res.json(profileFields) . This is the response I get when I use
profileFields
{
"user": "5b3134a0e2543b06d130a5d7",
"handle": "wadeaston1",
"status": "Developer",
"skills": [
"HTML",
" CSS",
" Javascipt"
],
"social": {}
}
i'm at a loss here because all my fields are passing in the values as expected into user and $set. I don't understand why its going to my catch
Profile.findByIdAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
)
.then(profile => res.json(profile))
.catch(err => {
res.json("Timeout");
console.log("HI");
});
Here is my Profile Schema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
//Create Scheme
const ProfileSchema = new Schema({
user: {
//this will associate user by their ID
type: Schema.Types.ObjectId,
ref: "users"
},
handle: {
type: String,
required: true,
max: 40
},
company: {
type: String
},
website: {
type: String
},
location: {
type: String
},
status: {
type: String,
required: true
},
skills: {
//Array of strings
type: [String],
required: true
},
bio: {
type: String
},
githubusername: {
type: String
},
experience: [
{
title: {
type: String,
required: true
},
company: {
type: String,
required: true
},
location: {
type: String
},
from: {
type: Date,
required: true
},
to: {
type: Date,
required: true
},
current: {
type: Boolean,
default: false
},
description: {
type: String
}
}
],
education: [
{
school: {
type: String,
required: true
},
degree: {
type: String,
required: true
},
fieldofstudy: {
type: String,
required: true
},
from: {
type: Date,
required: true
},
to: {
type: Date,
required: true
},
current: {
type: Boolean,
default: false
},
description: {
type: String
}
}
],
social: {
youtube: {
type: String
},
twitter: {
type: String
},
facebook: {
type: String
},
linkedin: {
type: String
},
instagram: {
type: String
}
},
date: {
type: Date,
default: Date.now
}
});
module.exports = Profile = mongoose.model("profile", ProfileSchema);
findByIdAndUpdate is for finding the document to update by its _id value, but you need to find the document by its user field, so you should be using findOneAndUpdate instead:
Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
)
.then(...
No need to manually cast req.user.id to an ObjectId as Mongoose will do that for you based on the way user is defined in your schema.
Based on the error you gave, it looks like you need to turn req.user.id from a string to an ObjectId:
Profile.findByIdAndUpdate(
{ user: new mongoose.Types.ObjectId(req.user.id) },
{ $set: profileFields },
{ new: true }
).then( /* rest of code */
This assumes you did a const mongoose = require('mongoose') or similar.

Categories