expressjs - mongoDb return nested subArray - javascript

im trying to create a seprate route in my api for a subArray from a nested array. using expressJs.
categories array:
const Categories = [
{
_id: 's654fs54s6d4f'
title: 'category 1',
SubCats: [
{
_id: 'jhgfsf68746'
name: 'subcat 1',
image: '/assets/images/vr-box-6203301_1920.jpg',
},
{
_id: 'vb40n5b4vn'
name: 'subcat 2',
image: '/assets/images/galaxy-s20_highlights_kv_00.jpg',
},
]
},
]
categoryModel:
import mongoose from 'mongoose'
const Catschema = mongoose.Schema({
name: {
type: String,
required: true,
},
image: {
type: String,
required: true,
},
})
const CategorySchema = mongoose.Schema(
{
title: {
type: String,
required: true,
},
SubCats: [Catschema]
},
{
timestamps: true,
}
)
const Category = mongoose.model('Category', CategorySchema)
export default Category
categoryController:
this would return the whole array
const getCategories = asyncHandler(async (req, res) => {
const categories = await Category.find({})
res.json(categories)
})
i want to return 'SubCats' array.
tried this but getting "SubCats is not defined".
const getSubCategories = asyncHandler(async (req, res) => {
const subcategories = await Category.find({SubCats})
res.json(subcategories)
})

find() returns an array and it takes in an object to query the db. In your question you used Category.find({SubCats}) which is Category.find({SubCats: SubCats}), which SubCats is not defined.
I think what you are looking for is Category.find().select('SubCats'), this will return an array of Categories with SubCats only.

Related

Pushing object to triple nested array in Mongoose

I am trying to figure out how to access and push an object into a triple nested array while using mongoose.
My idea is to divide a blog post into an array of chapters, where each has their own array of pages. Each page will have a title, image and body.
Story schema (parent document)
const mongoose = require('mongoose')
const pageSchema = require('./pageModel')
const storySchema = mongoose.Schema({
storyTitle: {
type: String,
required: [true, 'Title required.']
},
storyAuthor: {
type: String,
required: [true, 'Author required.']
},
storyImage: {
type: String,
required: true,
},
chapters: [{
chapterTitle: {
type: String,
//required: [true, 'Title required.']
},
chapterSummary: {
type: String,
// required: [true, 'Summary required.']
},
pages: [pageSchema]
}]
})
module.exports = mongoose.model('Story', storySchema)
the Page Schema
const mongoose = require('mongoose')
const pageSchema = mongoose.Schema({
pageTitle: {
type: String,
required: [true, 'Title required.']
},
pageBody: {
type: String,
},
pageImage: {
type: String,
}
})
module.exports = pageSchema;
Simple ops
const mongoose = require('mongoose')
const Story = require('./storyModel')
const Page = require('./pageModel')
const test = new Story({
storyTitle: 'Test',
storyAuthor: 'Myself',
storyImage: 'test',
});
console.log(test);
test.chapters.push({
chapterTitle: 'chapter 1',
chapterSummary: 'let us see',
})
const first = {
pageTitle: 'A page',
pageImage: 'image',
pageBody: 'A body'
}
console.log(test)
//test.chapters[0].pages[0].push(page)
test.chapters[0].pages.push(first)
console.log(test)
When I log each step, the parent is correctly made, and I am able to append a chapter to the chapters array. But when I the first object, the change isn't visible.
If I log test.chapters, the pages array shows pages: [ [Object] ]
And if I log test.chapters.pages, I just see 'undefined'.
Any suggestions and critique is appreciated.

Mongoose aggregation $lookup returns empty array in 'as' field

Let's say we have two collections: Order and Seller for an Ebay like business where customers can order items from individual sellers.
Each Order contains a seller field which lists the ID of the shop owner.
const orderSchema = new mongoose.Schema({
seller: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'Seller' },
item: { type: String },
});
const Order = mongoose.model('Order', orderSchema);
When I try to use $lookup
const aggregateOrdersWithSellerInfo = await Order.aggregate([
{
$lookup: {
from: 'Seller',
localField: 'seller',
foreignField: '_id',
as: 'seller_info',
},
},
]).exec();
all seller_info fields (ex: aggregateOrdersWithSellerInfo[0].seller_info) return an empty array:
> (0) []
But I would expect it to return the seller associated with the seller field on each Order such as:
// Seller doc
{
_id: ObjectId("62aa38d68e006f3006efe520"),
firstName: 'Nikki',
__v: 0
}
Here's an example of the Order doc
{
_id: ObjectId("62aa38d68e006f3006efe522"),
seller: ObjectId("62aa38d68e006f3006efe520"),
item: 'Mango Body Butter',
__v: 0
}
How to get the associated seller document using aggregation?
Full Code
const mongoose = require('mongoose');
const connect = async (dsn) =>
mongoose.connect(dsn, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
// Order Schema
const orderSchema = new mongoose.Schema({
seller: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'Seller' },
item: { type: String },
});
const Order = mongoose.model('Order', orderSchema);
// Seller Schema
const sellerSchema = new mongoose.Schema({
firstName: { type: String },
});
const Seller = mongoose.model('Seller', sellerSchema);
// Seeder
const seedLocalDatabase = async () => {
await connect('mongodb://127.0.0.1:27017/fakewishtender');
await Seller.deleteMany({});
const sellers = [
{
firstName: 'Nikki',
},
{
firstName: 'Alice',
},
];
const sellersInsertedRes = await Seller.insertMany(sellers);
await Order.deleteMany({});
const orders = [
{
seller: sellersInsertedRes.find((seller) => seller.firstName === 'Nikki')._id,
item: 'Mango Body Butter',
},
{
seller: sellersInsertedRes.find((seller) => seller.firstName === 'Alice')._id,
item: 'Vintage Jacket',
},
];
await Order.insertMany(orders);
};
// Aggregation
(async () => {
await seedLocalDatabase();
const aggregateOrdersWithSellerInfo = await Order.aggregate([
{
$lookup: {
from: 'Seller',
localField: 'seller',
foreignField: '_id',
as: 'seller_info',
},
},
]).exec();
const allSellers = await Seller.find({});
const allOrders = await Order.find({});
const sellersWithOrders = allOrders.map((order) =>
allSellers.filter((seller) => seller._id.toJSON() === order.seller.toJSON())
);
const sellersPopulatedWithAggregate = aggregateOrdersWithSellerInfo.map(
(order) => order.seller_info
);
console.log(
`
Sellers populated with aggregation are:
${JSON.stringify(sellersPopulatedWithAggregate)}
`
);
console.log(
`But I would expect sellers populated with aggregation to be:
${JSON.stringify(sellersWithOrders)}
`
);
mongoose.disconnect();
})();
the issue was the name of the collection.
Seller.collection.collectionName holds the collection name which was 'sellers' so plural and lowercase.
const aggregateOrdersWithSellerInfo = await Order.aggregate([
{
$lookup: {
from: 'sellers',
localField: 'seller',
foreignField: '_id',
as: 'seller_info',
},
},
]).exec();
You can also do from: Seller.collection.collectionName instead of statically typing the name

Save array of ObjectId's using Mongoose's Schema

I have a Mongoose Schema like:
const Role = new Schema({
guildID: {
type: Schema.Types.ObjectId,
ref: 'guilds',
required: true
},
roles: {
owner: {
id: {
type: Number,
required: false
},
commands: [[Schema.Types.ObjectId]]
}
}
})
And a small function to test whether it saves the data as desired which contains:
const roleTest = new Role({
guildID: "61a679e18d84bff40c2f88fd",
roles: {
owner: {
id: 123456789
},
commands: [
"61af57d828b9fd5a07dbdcba",
"61af5a6728b9fd5a07dbdcbb",
"61af5ab728b9fd5a07dbdcbc"
]
}
})
roleTest.save((err, doc) => {
if (err) return res.sendStatus(500)
console.log('Done')
})
It saves everything correctly except the array ObjectIds (commands). What is going wrong here?
You've written the commands in schema with nested array. Try with single array:
{
commands: [Schema.Types.ObjectId],
}
Try this:
commands: [
{ type: mongoose.Schema.Types.ObjectId }
]

How to add multiple items in model

I have a model called "list" where I have to put several items in it. But I made a code that can put only one item in a list. Can anyone help me solve this?
My model:
const mongoose = require('mongoose');
const { itemSchema } = require('./item.js');
const { shopSchema } = require('./shop.js');
const listSchema = mongoose.Schema({
name: { type: String, required: true },
created: { type: Date, required: true, unique: true },
updated: { type: Date },
items: [itemSchema],
shop: [shopSchema]
});
module.exports.ListData = mongoose.model("listData", listSchema);
module.exports.listSchema = listSchema;
itemSchema:
const mongoose = require('mongoose');
const categSchema = require("./category.js")
const itemSchema = mongoose.Schema({
name: { type: String, required: true },
created: { type: Date, required: true, unique: true },
category: [categSchema.categorySchema],
quantity: { type: Number, required: true }
});
module.exports.ItemData = mongoose.model("itemData", itemSchema);
module.exports.itemSchema = itemSchema;
How do I make "items:" to recieve multiple items, not just one? I am using mongodb for this project. Thanks!
Your items already accepts multiple items. Is this not what you want? I tested with this little experiment:
import connect from './db.js';
import mongoose from 'mongoose';
// this just connects to mongodb
await connect();
const itemSchema = mongoose.Schema({
name: { type: String, required: true }
});
const ItemData = mongoose.model("itemData", itemSchema);
const listSchema = mongoose.Schema({
name: { type: String, required: true },
items: [itemSchema]
});
const ListData = mongoose.model("listData", listSchema);
await ListData.deleteMany({});
// create items
await ItemData.create({ name: "potato" });
await ItemData.create({ name: "tomato" });
await ItemData.create({ name: "kitten" });
const items = await ItemData.find({});
await ItemData.deleteMany({});
// create list
await ListData.create({
name: "Stuff i luv",
items
});
// get inserted lists
const q = ListData.find();
q.select("-__v -_id -items.__v -items._id");
const ld = await q.exec();
// print results
console.log(JSON.stringify(ld));
// result is
[{
"name":"Stuff i luv",
"items":[{"name":"potato"},{"name":"tomato"},{"name":"kitten"}]
}]

.populate() not working

I have been working on this for hours and can't find a solution.
I am making a school directory using a
Student Model:
var mongoose = require("mongoose");
var studentSchema = new mongoose.Schema(
{
name: String,
courses: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Course"
}
]
});
module.exports = mongoose.model("Student", studentSchema);
and a Course Model...
var mongoose = require("mongoose");
var courseSchema = new mongoose.Schema (
{
name: String,
student: [
{
id:
{
type: mongoose.Schema.Types.ObjectId,
ref: "Student"
},
name: String
}
]
}
);
module.exports = mongoose.model("Course", courseSchema);
When I run .populate on a found student... it does not populate the Course values within the Student...
app.get("/students/:id", function(req, res){
Student.findById(req.params.id).populate("courses").exec(function(err, foundStudent){
if(err){
console.log(err);
} else {
console.log(foundStudent);
res.render("students/show", {student: foundStudent});
}
});
});
The console.log(foundStudent) will display...
{ _id: 597e7a49c945ee13529d0871,
name: 'Collin DeSoto',
__v: 1,
courses: [ { _id: 597e7a4dc945ee13529d0872 } ] }
AFTER the populate.. any ideas?
try this way
User.find(match, function (err, users) {
var opts = [{ path: 'company', match: { x: 1 }, select: 'name' }]
var promise = User.populate(users, opts);
promise.then(console.log).end();
})
and prefar this link link

Categories

Resources