Mongoose - Find document's child array by a specific field - node.js

I had spent hours trying to work out how to get records from a document's child array by a specific field, but I failed it.
I would like to pass a personId by a web service to find which meeting he/she has been invited to. As a result, I could track down whether the invitee has accept to join the meeting or not.
Basically, I have the following JSON output:
{
"status": "success",
"requestedAt": "2021-03-28T22:47:03+11:00",
"size": 1,
"meetings": [
{
"invitedMembers": [
{
"isJoined": false,
"_id": "605ffbc00a21ed718c992549",
"person": "a123",
"__v": 0
}
]
}
]
}
with a controller like this:
const memberId = "a123";
const meetings = await Meeting.find({
'invitedMembers.member': memberId
}).populate('invitedMembers');
a meeting model class like below:
const mongoose = require('mongoose');
const meetingSchema = new mongoose.Schema({
invitedMembers: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'InvitedMembers'
}
]
});
const Meeting = mongoose.model(
'Meeting',
meetingSchema
);
module.exports = Meeting;
and a invitedMembers class like this:
const mongoose = require('mongoose');
const invitedMembersSchmea = new mongoose.Schema({
member: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Member',
required: true
},
isJoined: {
type: Boolean,
default: false
}
});
const InvitedMembers = mongoose.model(
'InvitedMembers',
invitedMembersSchmea
);
module.exports = InvitedMembers;
The Member schema only contains a basic personal information such as first name, last name and etc.

I ended up solving my own problem by using a different approach where I changed my data structure by adding invitedMembers as an embedding model in the meeting model and updated the person field in the invitedMembers schema to _id.
Updated Meeting model class:
const mongoose = require('mongoose');
const invitedMembersSchmea = new mongoose.Schema({
_id: {
type: String,
required: true
},
isJoined: {
type: Boolean,
default: false
}
});
const meetingSchema = new mongoose.Schema({
invitedMembers: [
{
type: invitedMembersSchmea
}
]
});
const Meeting = mongoose.model(
'Meeting',
meetingSchema
);
module.exports = Meeting;
As a result, I can find the invited member by ID using the following query:
const memberId = "a123";
const meetings = await Meeting.find({
'invitedMembers._id': memberId
});

Related

mongoose save internal documents creating a document that contains a document

Im learning mongoose and i have a question how to save several documents:
// Product.js
const categorySchema = mongoose.Schema(
{ name: String },
{ collection: "categories" }
);
const productSchema = mongoose.Schema(
{ name: String, category: categorySchema },
{ collection: "products" }
);
modules.exports = mongoose.model("Product", productSchema);
The idea is that when I create a product this way
const Product = require("./Product.js")
const product = new Product({name: 'Soccer Ball', category: {name: "Sports"})
await product.save()
i want to get a document in the collection products and also a document in the collection categories
how can it be possible
thanks in advance
PD : Im getting this but category is not save in the collection
{
"msg": "Product created succesfully",
"ok": true,
"product": {
"name": "Soccer ball",
"category": {
"name": "Sports",
"_id": "6275df4c8149967bea21e7c0"
},
"_id": "6275df4c8149967bea21e7bf",
"__v": 0
}
}
You should define your Product's category as a ref attribute:
// Product.js
const categorySchema = mongoose.Schema(
{ name: String },
{ collection: 'categories' }
);
const productSchema = mongoose.Schema(
{
name: String,
category: { type: mongoose.Schema.Types.ObjectId, ref: 'categories' },
},
{ collection: 'products' }
);
modules.exports = {
Category: mongoose.model('Category', categorySchema),
Product: mongoose.model('Product', productSchema),
}
Doing this you will need to assign the _id of the category to the new Product:
const { Category } = require("./Product.js")
const { Product } = require("./Product.js")
// Create category (supposing it is not present)
const category = new Category({ name: "Sports" })
await category.save()
// Add category _id to product
const product = new Product({name: 'Soccer Ball', category: category._id})
await product.save()
Finally, you will be able to retrieve the product by using populate:
const product = await Product.findById(<product_id>).populate('categories').exec()
This query should give the same result than before, but the Category data will be loaded from the reference in the Category collection.

How to delete an object from an array in a mongoose Schema?

User Schema
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,
},
todo : [{ type : mongoose.Schema.Types.Mixed,ref : 'Todo'}]
})
const User = mongoose.model('User',UserSchema);
module.exports = User;
Todo Schema
const TodoSchema = ({
task : String
})
const Todo = mongoose.model('Todo', TodoSchema)
module.exports = Todo;
Database
How do I delete a single todo object i.e("Task 1") from the user?
router.get('/delete/:id',ensureAuthenticated, (req,res)=>{
id = req.params.id
user = req.user
User.update({ }, { "$pull": { task: id }});
tasks = user.todo
res.render("todo/all",{
todo:tasks,
});
})
I have tried all the stackoverflow threads for over 4 hours and I still coudn't figure out what's wrong. Really apprecitate it if you could help it out.
Thank You :)

How to use $lookup in a project where there are multiple databases?

Here's my product.model.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema; var ObjectId = mongoose.Schema.Types.ObjectId;
const ProductModel = new Schema(
{
name: {
type: String
},
//hidden code for better viewing
policyId: {
type: mongoose.Schema.Types.ObjectId
}
},
{
strict: false,
timestamps: true
}
);
const myDB = mongoose.connection.useDb('SampleDB');
module.exports = myDB.model('bf-product', ProductModel);
Here's my return-policy.model.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = mongoose.Schema.Types.ObjectId;
const ReturnPolicyModel = new Schema(
{
name: {
type: String
},
description: {
type: String
},
addedById: {
type: String
},
status: {type: Number, default: 1}
},
{
strict: false,
timestamps: true
}
);
const myDB = mongoose.connection.useDb('SampleDB');
module.exports = myDB.model('bf-return-pol', ReturnPolicyModel);
Here's the query I'm running
const Product = require('../models/product.model');
let products = await Product.aggregate([
{
$lookup:
{
from: "bf-return-pol",
localField: "policyId",
foreignField: "_id",
as: "policies"
}
}
])
console.log(products)
When I run the query, policies always returns empty. I think the issue is because of the project using multiple databases, as I had a similar issue with paths with the populate keyword. So my question is this, how can I run the query as both the collections are in the same db?
product collection
return-policy collection
EDIT: The issue seemed to be that the collection was named as "bf-return-pols" and once I changed the from field in lookup, I could get the results.

Mongoose fetch data from collection A if it's reference exists on collection B

I need your help please with a mongoose query for my express app.
I have 3 collections Movies, TvShows and Trailers and I need to fetch all movies or shows that have trailers.
here are the models:
var TrailerSchema = new Schema(
{
link: {
type: String,
required: true,
},
movieId: { type: mongoose.Schema.Types.ObjectId, ref: 'Movie' },
showId: { type: mongoose.Schema.Types.ObjectId, ref: 'Show' },
}
)
module.exports = mongoose.model('Trailer', trailerSchema)
const mongoose = require('mongoose')
const Schema = mongoose.Schema
var movieSchema = new Schema(
{
title: {
type: String,
required: true,
},
rating: {
type: Number,
},
}
)
module.exports = mongoose.model('Movie', movieSchema)
in the Trailer collection there are some documents with the movieId field and some with showId.
Now how can I fetch all the movies or shows that have trailers?
because you just stored movieId in TrailerSchema and movieSchema don't have field like TrailerId:[{type: mongoose.Schema.Types.ObjectId, ref: 'Trailer'}], can not use populate...
but for your issue at first
let listOfIds = await Link.find( { movieId: { $exists: true } }, 'movieId._id' ).lean()
I don't know real data stored in Trailer collection for query in Trailer.find after get IDs you should search in Movie collection to get all info
let listOfMovies = await Movie.find({ _id: { $in: listOfIds.map((id) => {if(id.movieId) return id.movieId._id} ) }, })

How to add item to mongoose Array

I'm developing a web app that uses mongodb database using mongoose in node.js...
Now, I'm trying to build the rate feature, in this feature, people can rate the store and give some comments about that store.
This is the structure:
rate: {
author: req.body.author,
text: req.body.text
}
To update it I'm using the "findOneAndUpdate" function, but, Always when i do it, the existent rate is overwritten by the new... Can you guys help me?
Here you can do. I am just demonstrating with example
Model
//Model
const ratingSchema = new mongoose.Schema({
author: { type: String, required: true },
text: { type: String, required: true }
});
const productSchema = new mongoose.Schema({
name: { type: String, required: true },
description: { type: String },
rating: [ratingSchema],
price: { type: Number, default: 1 },
});
module.exports = mongoose.model('Product', productSchema );
Now you can just push a new array
Controller
const ProductModel = require('./models/product');
const { id } = req.params;
const { author, text } = req.body;
PersonModel.update(
{ _id: id },
{ $push: { rating: { author, text }} },
done
);
More about: https://mongoosejs.com/docs/api/array.html#mongoosearray_MongooseArray-push
Try this one
The model
const schema = new mongoose.Schema({
name: String,
description: String,
price: Number,
rating: [{
author : String,
text : String
}]
});
module.exports = mongoose.model('Product', schema );
In request handler
const Product = require('./models/product');
const { id } = req.params; //product ID
const { author, text } = req.body;
const product = Product.findById(id);
product.rating = [...product.rating,{ author, text }]
product.save();
One way is with regular JS, you can simply store the document you want to update in a variable. Then, use the push method on the rate field before calling save on the variable.

Resources