Fetching an array of document objects with different IDs from a document - javascript

I am attempting to show only documents from users in which the session user is subscribed to (in mongo using mongoose). The subscribed users are added to a 'following' array inside the user document. The user can only see objects (posts) from that array.
I am using node express. Here is the attempt using the populate method from mongoose.
var user = req.user;
var posts = [];
Post.populate(posts, {path: "post.creator", match: {'creator': user.following}}, function (err, posts) {
if (err) {
return next(err);
}
posts.forEach(function (post) {
posts.push(post);
});
console.log(posts);
return res.render('subscribed', {posts: posts, user: user});
});
I am new to mongoose, and have only been fetching bulk documents with no queries up until now.
The user model is made up as such:
//required stuff and set up
...
//user object
var UserSchema = Schema({
username: {
type: String,
},
posts: [{
type: Schema.Types.ObjectId,
ref: 'Post'
}],
following: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
followers: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
)}
//exports etc
...
And the post schema
//required stuff and set up
...
//post object
var PostSchema = Schema({
title: {
type: String,
required: true,
trim: true
},
createdAt: {
type: Date,
default: Date.now
},
creator: {
type: Schema.Types.ObjectId,
ref: 'User'
}
});
//exports etc
...
Any help would be greatly appreciated.

Related

How to save an array of strings in mongodb

I have found a few similar questions on stack overflow like this one:
How to save array of Strings in Node Mongodb
Mongoose - Save array of strings
but I cant figure out why my method is not working
I am trying to save the string of arrays "jobType".
context: I am creating an app where people can post jobs.
each job can have multiple types.
here is my job model::
const mongoose = require("mongoose");
const postSchema = mongoose.Schema({
content: { type: String, required: true },
imagePath: { type: String, required: true },
state: { type: String, required: true },
substate: { type: String, required: true },
address: { type: String, required: true },
jobType: { type: [String] },
creator: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true }
});
module.exports = mongoose.model("Job", postSchema);
this is the API used to save the data on MongoDB:
I am 100% sure that the data is getting to the API correctly.
the parameter "req.body.jobtype" contains all the info as a string.
I am trying to use JSON.parse to change the string into an array but its not working.
when I check MongoDB, an empty array is being stored
const Job = require("../models/job");
exports.createJob = (req, res, next) => {
console.log('create job api hit')
const url = req.protocol + "://" + req.get("host");
const post = new Job({
content: req.body.content,
imagePath: url + "/images/" + req.file.filename,
creator: req.userData.userId,
state: 'new',
substate: 'new',
address: req.body.address,
jobtype: JSON.parse(req.body.jobtype) // fix: not storing correctly
});
post
.save()
.then(createdJob => {
res.status(201).json({
message: "Job added successfully",
post: {
...createdJob,
'pecker':'pecker hecks out',
id: createdJob._id
}
});
})
.catch(error => {
res.status(500).json({
message: JSON.stringify(error)
});
});
};
You have a typo. In your model, you defined jobType property, but when saving the data, you are passing it as jobtype.
So, instead of this:
jobtype: JSON.parse(req.body.jobtype)
Do this:
jobType: JSON.parse(req.body.jobtype)

Mongoose filter by nested reference

I have 3 mongoose schemas Employee, Team and Project. Employee has reference to the team and Team has reference to the Project. Is it possible to get all employees by project Id? I don't want to change schema or use Team model with populate.
const employeeSchema = mongoose.Schema({
email: { type: String, required: true, unique: true },
team: { type: mongoose.Schema.Types.ObjectId, ref: "Team" },
});
const teamSchema = mongoose.Schema({
name: { type: String, required: true },
employees: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
project: { type: mongoose.Schema.Types.ObjectId, ref: "Project" },
});
Below code throws cast error, id is a valid project id.
router.get("/:id/employees", checkAuth, (req, res, next) => {
const id = req.params.id;
console.log(id);
Employee.find({ team:{project:id}}).then((employees) => {
console.log(employees);
});
});
Yes it is possible to get all employees using project Id.but not using single query so you have to modify your function like this
const id = mongoose.Types.ObjectId(req.params.id);
Team.findOne({ project: id }, { _id: 1 }, function (err, docs) {
// Get the Team which match with project ID
Employee.find({ team: docs._id }, function (err, docs1) {
//Get all employee belongs to that team and project
console.log(docs1);
});
});

How to push an object into an array with GraphQL?

I would like to change the way my resolver is creating the payment cards in my DB. So now I create the wallet in one collection then a payment in another collection and use the wallet_id to in my payment to link them. But now I want to push the payments into a cards[] that is defined in wallet. Any idea how to do that in resolver?
This is my Wallet schema
const WalletSchema = new Schema({
tokens: {
type: Number,
default: 0
},
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
unique: true
},
cards: [
{
type: Schema.Types.ObjectId,
ref: 'Payment'
}
]
}, { timestamps: true });
and this is my createPayment resolver
createPayment: async (_, { wallet_id, ...args }, { user }) => {
try {
await requireAuth(user);
const payment = await Payment.create({ ...args, wallet: wallet_id });
pubsub.publish(PAYMENT_ADDED, { [PAYMENT_ADDED]: payment });
return payment;
} catch (error) {
throw error;
}
},
Any idea?
You need to create another Schema for card payments;
const WalletSchema = new Schema({
tokens: {
type: Number,
default: 0
},
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
unique: true
},
cards: [ PaymentSchema ] <-- here
}, { timestamps: true });
// new schema
const PaymentSchema = new Schema({
type: Schema.Types.ObjectId,
ref: 'Payment'
});
Based on Wallet schema you need to write expose graphql schema

Mongoose query condition inside a list

I am not sure how to make the title of this question a bit more clear :)
So let me jump directly to the schema:
const UserSchema = new Schema({
name: String,
_events: [{ type: Schema.Types.ObjectId, ref: "Event" }]
});
Basically a user can have a number of events that are referenced by another model, Event. The event collection looks like this:
const EventSchema = new Schema({
_userId: { type: Schema.Types.ObjectId, ref: "User" },
eventDate: { type: Date, required: true },
instructions: String,
});
I am doing a query on Mongoose that lists all the events created by the user, as follows:
app.get("/api/events/", requireAuth, async (req, res, next) => {
try {
const userEvents = await User.findById(req.user._id)
.populate({
path: "_events",
model: "Event",
})
.select({ _events: 1 })
.exec();
res.send(userEvents);
} catch (err) {
next(err);
}
});
This works perfectly. However I am interested in listing only future events. How can I modify the query to do a condition where eventDate > current date?
You should query for that in the populate function as follows:
Here:
.populate({
path: "_events",
model: "Event",
})
Add this:
match: { eventDate: { $gte: Date.now() } }

How to save document based on user id using mongoose?

I am trying to save template based on user id , How can i make sure when template save it save with user id _id ? i added reference to the templateSchema for User.
user.model.js
var UserSchema = new mongoose.Schema({
_id: { type: String, required: true, index: {unique: true}},
firstName: String,
lastName: String,
type: String,
groups:[{type: String, ref: 'Group', required: false}]
},
{
toObject: {
virtuals: true
},
toJSON: {
virtuals: true
}
});
export default mongoose.model('User', UserSchema);
template.model.js
var User = require('../user/user.model.js');
var TemplateSchema = new mongoose.Schema({
_id: { type: String, required: true},
name: String,
id: String,
appliesTo: [],
properties: [],
createdBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User'}
});
export default mongoose.model('Templates', TemplateSchema);
template.controller.js
var eTemplate = require('./template.model');
export function create(req, res) {
console.log(req.body);
eTemplate.createAsync(req.body)
.then(responseWithResult(res, 201))
.catch(handleError(res));
}
Mongoose has two built-in functions that are called before (pre) and after (post) you save a document. My advice is to make use of them. Here is an example of my code in which I search for an sequence number before saving the user document. You can do the same: When you save the template, make a request for the user id to the database (Or vice-versa). You can even save one, get the id and save the other.
Bellow follows my code for the sequence and the user.
var UserSchema = new Schema({
username: { type: String, required: true, unique: true },
id: { type: String },
...
});
UserSchema.pre('save', function(next) {
let doc = this;
let id = 'userSeq'
Sequence.findByIdAndUpdate(id, { $inc : {nextSId : 1} }, function(error,data) {
if(error)
next(error)
doc.id = data.nextSId-1;
next();
})
});
I hope my answer was useful for you. Just a remark, pre and post are not called in the event of updates for the document.

Categories