mongoose save internal documents creating a document that contains a document - node.js

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.

Related

How to create array of object ids in ref mongoose?

I am trying to create an order in the post method. I have two documents - Order, OrderItem. Schemas are-
var OrderSchema = new Schema({
name: String,
orderItems : [{ type: Schema.Types.ObjectId, ref: 'orderitems' }]
});
var orderItemsSchema = new Schema({
name: String,
products : String
});
My controller function --
let itemArr: any[] = [];
req.body.orderItems.map(async (item: { products: any; quantity: any }) => {
const newOrdeItem = new OrderItems({
products: item.products,
quantity: item.quantity,
});
const items = await newOrdeItem.save();
//found ids
itemArr.push(items._id);
});
//not found ids
itemArr.push(items._id);
const newOrder = new Order({
orderItems: itemArr,
phone: req.body.phone,
});
const order = await newOrder.save();
return res.json(order);
I want to make an order. req.body data are--
{
"orderItems" : [
{
"quantity": 3,
"product" : "Orange"
},
{
"quantity": 2,
"product" : "Banana"
}
],
"phone": "+420702241333",
}
How can I solve this issue?
I understand you need to get the orderItems from the ref ? if that can you use populate
order.populate('orderItems')
//Edit
frist require your model from monngoose
after that make insertMany or save fn
like
const dbOrders = require('pathOfModel')
orderResult = await dbOrders.insertMany({
name : req.body.name || 'Name you need insert in Schema',
orderItems : itemArr
})
console.log(orderResult) // res.json(orderResult)

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

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
});

How to paginate array of key values using mongoosePaginate?

I created Category Schema where there is Array of Products I want to paginate items of array not category it self, How can I fix this issue???
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const mongoosePaginate = require('mongoose-paginate-v2');
const categorySchema = new Schema({
category: {
type: String,
required: true,
}
items:[{
title: {
type: String,
required: true,
},
price: {
type: String,
required: true,
},
}]
});
categorySchema.plugin(mongoosePaginate);
const Category = mongoose.model('Category', categorySchema);
module.exports = Category;
if I do it like this it wont work it says "category.items.paginate is not a function"
let category = await Product.findOne({ category: mycategory })
let categoryItemsPagenateResult = category.items.paginate()
for this situation you don't need to any plugin, just use $slice like this:
let skip = 0
let limit = 3;
let x = await Product.findOne({ category: mycategory }).select({ 'items': { '$slice': [skip,limit] } }).lean()
in x.items you have result

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 do we create a reference to a collection with mongoose

Please forgive me if this question seems related to the one I already asked before, I feel I didn't really put the question well the first time.
I have created a resource route based on the following data seeded into Mongodb from my application
// seeder.js
"_id": "5d7a514b5d2c12c7449be020",
"issuedBy": "Ola",
"collectedBy": "Ola",
"quantity": "8",
"product": "5d713995b721c3bb38c1f5d0",
My question is this; How do i actually save the product objectId "5d713995b721c3bb38c1f5d0" on the Orders collection
exports.getOrders = asyncHandler(async (req, res, next) => {
if (req.params.productId) {
const orders = await Orders.find({ product: req.params.productId });
return res.status(200).json({
success: true,
count: orders.length,
data: orders
});
} else {
res.json(orders);
}
});
With the above route, I am setting a condition that's based on the presence of a ProductId in the URL that will be matched inside the Orders collection "Orders.find({ product: req.params.productId })"
//Product Schema
const ProductSchema = new mongoose.Schema({
name : String,
description : String,
price : Number,
quantity : Number,
supplier :String
},{timestamps:true});
module.exports = mongoose.model('Product', ProductSchema)
// Orders Schema
const OrderSchema = new mongoose.Schema({
issuedBy : String,
collectedBy: String,
quantity: Number,
product: {
type: mongoose.Schema.ObjectId,
ref: 'Product',
required: true
},
},{timestamps:true});
const Orders = mongoose.model("Orders", OrderSchema);
// Export model
module.exports = Orders;
How do I actually create a route that saves the productId in the Orders collection like these "product": "5d713995b721c3bb38c1f5d0"?
I think an order can have multiple products. So I changed the name of product to producs, and made it array.
Also, for model names it is better to use singular naming convention.
I would set up my schemas and models like this:
Product model:
const mongoose = require("mongoose");
const ProductSchema = new mongoose.Schema(
{
name: String,
description: String,
price: Number,
quantity: Number,
supplier: String
},
{ timestamps: true }
);
module.exports = mongoose.model("Product", ProductSchema);
Order model:
const mongoose = require("mongoose");
const OrderSchema = new mongoose.Schema(
{
issuedBy: String,
collectedBy: String,
quantity: Number,
products: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Product",
required: true
}
]
},
{ timestamps: true }
);
module.exports = mongoose.model("Order", OrderSchema);
You can create an order with products with this code:
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const url = "mongodb://localhost:27017/ord";
const Order = require("./models/order");
const Product = require("./models/product");
const port = 3000;
app.use(express.json());
mongoose
.connect(url, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
app.listen(port, () => {
console.log(`App running on port ${port}...`);
});
})
.catch(error => console.log(error));
app.post("/order", async (req, res) => {
let result = await Order.create(req.body);
res.send(result);
});
app.get("/order/:orderId", async (req, res) => {
const result = await Order.findById(req.params.orderId).populate("products");
res.send(result);
});
You can create an order with products to the http://localhost:3000/order with this body: (you must use your existing product ids)
{
"issuedBy": "issuedBy",
"collectedBy": "collectedBy",
"quantity": 123,
"products": ["5ddfb388b14c5b41e0607a5e","5ddfb376b14c5b41e0607a5d"]
}
Response:
{
"products": [
"5ddfb388b14c5b41e0607a5e",
"5ddfb376b14c5b41e0607a5d"
],
"_id": "5ddfb418b14c5b41e0607a5f",
"issuedBy": "issuedBy",
"collectedBy": "collectedBy",
"quantity": 123,
"createdAt": "2019-11-28T11:48:40.500Z",
"updatedAt": "2019-11-28T11:48:40.500Z",
"__v": 0
}
When you want to get this order and its products, you need to send a GET request to the http://localhost:3000/order/5ddfb418b14c5b41e0607a5f the id in the url is the the id of the order we previosly created, so you need to use your order id.
If you want also to be able to add a product to an existing order, you can add this code:
app.post("/order/:orderId/:productId", async (req, res) => {
const result = await Order.findByIdAndUpdate(
req.params.orderId,
{
$push: {
products: req.params.productId
}
},
{ new: true }
);
res.send(result);
});
So the POST url must contain the orderId and productId like this:
http://localhost:3000/order/5ddfb418b14c5b41e0607a5f/5ddfb67c721b885790ec837b
Response:
{
"products": [
"5ddfb388b14c5b41e0607a5e",
"5ddfb376b14c5b41e0607a5d",
"5ddfb67c721b885790ec837b"
],
"_id": "5ddfb418b14c5b41e0607a5f",
"issuedBy": "issuedBy",
"collectedBy": "collectedBy",
"quantity": 123,
"createdAt": "2019-11-28T11:48:40.500Z",
"updatedAt": "2019-11-28T11:59:51.659Z",
"__v": 0
}

Resources