how to use find function in nodejs - javascript

const categorySchema = mongoose.Schema({
name: {
required: true,
type: String
}
});
const productSchema = mongoose.Schema({
name: {
type: String,
required: true
},
category: {
type: mongoose.Schema.Types.Mixed,
ref: "Category",
required: true
}
});
As you see above I have two models where I am using Category inside Product.
Now I want to fetch all the products by passing a particular Category or its id as _id which gets generated by default by mongodb.
Although I am achieving the desired result do this below:
const id = req.query.categoryId;//getting this from GET REQUEST
let tempProducts = [];
let products = await Product.find({});
products.forEach(product => {
if (product.category._id===id){
tempProducts.push(product);
}
});
It gets me what I want to achieve but still I want to know how to get it using "find" function. or this what I am doing is the only way.

Ok thank you all for your time. I found out the solution which is:
First of all below is my schema as Product which includes another schema named Category:
const productSchema = mongoose.Schema({
name: { type: String, required: true },
category: { type: mongoose.Schema.Types.Mixed, ref: "Category", required: true } });
And to get all the products related to a particular category,
We need to add our query inside quotes like this:
let tempProducts = [];
tempProducts = await Product.find({ "category._id": id});
This is how I achieved as I wanted and working as expected.

Related

Mongoose - Best way to get followers posts

I am building a social media and one of the features I have is the ability to follow other users and have their posts show up on a home page, much like an Instagram feed. I have an endpoint that loops through all the users you are following and gets the post that are rated for your age, sorts them and puts them in an array.
router.get("/following", auth, async (req, res) => {
try {
const user = await User.findOne({ firebaseUID: req.authId });
const dob = dayjs(user.dob.toISOString().split("T")[0]);
const currentDate = dayjs(new Date().toISOString().split("T")[0]);
const age1 = currentDate.diff(dob, "year");
let posts = [];
for (let i = 0; i < user.following.length; i++) {
posts.push(
await Post.find({
userID: user.following[i].user,
age: { $lte: age1 },
})
);
}
posts = [].concat.apply([], posts);
posts = _.sortBy(posts, "date").reverse();
res.json(posts);
} catch (err) {
console.error(err.message);
res.status(500).json({ msg: "Server Error" });
}
});
The user schema looks like this
const UserSchema = new Schema({
firebaseUID: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
username: {
type: String,
required: true,
unique: true,
},
avatar: {
type: String,
},
dob: {
type: Date,
default: Date.now,
required: true,
},
slug: {
type: String,
},
following: [
//array of user IDs
{
user: {
type: Schema.Types.ObjectId,
ref: "users", //here so we know which lieks came from which users
},
},
],
followers: [
//array of user IDs
{
user: {
type: Schema.Types.ObjectId,
ref: "user", //here so we know which lieks came from which users
},
},
],
});
The problem is that I am trying to add infinite scroll pagination to the front end that will start by getting the first 15 posts and then get the next 15 and so on from endpoints that provide this.
What would the best way to do this be? For other routes, I have used .skip() and .limit(). I could split the array of posts up right before I send it as a response, but is there a way to do without getting all the posts as this would be taxing if you're following 100s of people with 1000s of posts.
I would need to loop through all the users you are following and get all their posts in line with your age rating but only get the first 15 sorted in date order from newest to oldest. Is there a mongoose function that I could use or would the best way be to split the array of posts?
Thank you.

Express: return is not showing array in api

So I have collections of Teacher, Classes. to understand my problem its necessary to understand my database. the structure is
const TeacherSchema = new Schema(
{
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
role: {
type: String,
default: "teacher"
},
userid: {
type: String,
required: true
},
password: {
type: String,
required: true
},
profileImage: {
type: String,
required: false
},
classes: [{
type:Schema.Types.ObjectId,
ref:'class'
}]//1 teacher will have multiple classes
},
{ timestamps: true }
);
and the class:
const ClassSchema = new Schema(
{
subject: {
type: String,
required: true
},
teacher:[{
type:Schema.Types.ObjectId,
ref: 'teacher'
}],//once class will have only one teacher
},
{ timestamps: true }
);
What i want to do is, I want to show teacher how many classes he/she has. here is my controller.
exports.getAllClass= async (req, res, next) => {
let teacherClasses
try{
teacherClasses= await Teacher.findById(req.params.id)//teacher database
arrayOfClass= teacherClasses.classes //getting the class it has array of objectID
arrayOfClass.forEach(async (classes)=>{
let classDB =await Class.findById(classes)
console.log(classDB.subject)// in the console it shows all the classes.
return res.status(200).json({
'name':classDB.subject //but here it only shows one class,the first class name
})
});
}catch(err){
console.log(err)
}
}
I have tried many thing, but cant reach to a proper solution. Can you tell me what did i do wrong here or is there any better approach? I want to show all the classes in the return. I am new in programming hence assigned in complex task, please help me.
You are using forEach on the arrayOfClass and within that forEach you return and send the response. So as soon as the first promise is resolved, the response is sent.
One simple way to do this is to use a for .. of loop and await each class-promise inside and keep track of each result. Once that's done you can send the response:
...
const classes = [];
for(const classId of arrayofClass) {
const classDB = await Class.findById(classId);
classes.push({ name: classDB.subject });
}
return res.json(classes);
Another way to do this is to use Promise.all() which might be better if you're dealing with a bigger dataset as is processes in parallel whereas the first solution processes in sequence:
...
const classPromises = await Promise.all(arrayofClass.map(classId => Class.findById(classId)));
const result = classPromises.map(classDB => ({
name: classDB.subject
}));
return res.json(result);

How do I find if an Id is present in the array of team members (which stores user ids)?

I have this model of workspace schema in my node js project(model is displayed below)
After the user logs into my application I want to display the information of a workspace only if it is created by him or he is a team member of that workspace
I am able to find the workspaces created by the user by the following query
Workspace.find({creator:req.user._id},function(err,workspaces){
res.render('home',{
wokspacses:workspaces
});
});
similarly, I also want the workspaces in which the user is the team member
Workspace.find({creator:req.user._id},function(err,workspaces){
Workspace.find({team_member:"WHAT SHOULD I WRITE HERE"},function(err,workspaces2){
res.render('home',{
wokspacses:workspaces
wokspacses2:workspaces2
});
});
Since team_members is an array simply passing the user id is not yielding the result and workspaces2 remains empty
Thank you for your time !!
const mongoose = require('mongoose');
const workspaceSchema = mongoose.Schema({
name:{
type:String,
required:true
},
date: {
type: Date,
required: true
},
creator:{
type: Object,
ref: 'User',
required: true
},
team_member: [{ type: Object, ref: 'User' }]
});
module.exports = mongoose.model('Workspace',workspaceSchema);
Use the $in Operator.
const mongoose = require("mongoose")
const Schema = mongoose.Schema
mongoose.connect('mongodb://localhost/stackoverflow', {useNewUrlParser: true});
const workspaceSchema = new Schema({
name:{
type:String,
required:true
},
date: {
type: Date,
required: true
},
creator:{
type: Object,
ref: 'User',
required: true
},
team_member: [{ type: Object, ref: 'User' }]
});
const WorkspaceModel = mongoose.model('Workspace',workspaceSchema);
const sessionUserId = "5d330f3de87ec83f95504c44" //i.e. req.user._id;
WorkspaceModel.find({
$or:[
{ creator: sessionUserId },
{
team_member: {
$in: [sessionUserId]
}
}
]
}).exec((err, result) => {
console.log("result", result)
})

MongooseJS returning empty array after population

I'm coding an app using Node.js and MongooseJS as my middleware for handling database calls.
My problem is that I have some nested schemas and one of them is populated in a wrong way. When I track every step of the population - all of the data is fine, except the devices array, which is empty. I double checked the database and there is data inside that array, so it should be fine.
I've got Room schema. Each object of Room has a field called DeviceGroups. This field contains some information and one of them is an array called Devices which stored devices that are assigned to the parent room.
As you can see in the code, I am finding a room based on it's ID that comes in request to the server. Everything is populated fine and data is consistent with the data in the database. Problem is that the devices array is empty.
Is that some kind of a quirk of MongooseJS, or am I doing something wrong here, that devices array is returned empty? I checked in the database itself and there is some data inside it, so the data is fine, the bug is somewhere in the pasted code.
The code:
Schemas:
const roomSchema = Schema({
name: {
type: String,
required: [true, 'Room name not provided']
},
deviceGroups: [{
type: Schema.Types.ObjectId,
ref: 'DeviceGroup'
}]
}, { collection: 'rooms' });
const deviceGroupSchema = Schema({
parentRoomId: {
type: Schema.Types.ObjectId,
ref: 'Room'
},
groupType: {
type: String,
enum: ['LIGHTS', 'BLINDS', 'ALARM_SENSORS', 'WEATHER_SENSORS']
},
devices: [
{
type: Schema.Types.ObjectId,
ref: 'LightBulb'
},
{
type: Schema.Types.ObjectId,
ref: 'Blind'
}
]
}, { collection: 'deviceGroups' });
const lightBulbSchema = Schema({
name: String,
isPoweredOn: Boolean,
currentColor: Number
}, { collection: 'lightBulbs' });
const blindSchema = Schema({
name: String,
goingUp: Boolean,
goingDown: Boolean
}, { collection: 'blinds' });
Database call:
Room
.findOne({ _id: req.params.roomId })
.populate({
path: 'deviceGroups',
populate: {
path: 'devices'
}
})
.lean()
.exec(function(err, room) {
if (err) {
res.send(err);
} else {
room.deviceGroups.map(function(currentDeviceGroup, index) {
if (currentDeviceGroup.groupType === "BLINDS") {
var blinds = room.deviceGroups[index].devices.map(function(currentBlind) {
return {
_id: currentBlind._id,
name: currentBlind.name,
goingUp: currentBlind.goingUp,
goingDown: currentBlind.goingDown
}
});
res.send(blinds);
}
});
}
})
This is an example of using discriminator method to be able to use multiple schemas in a single array.
const roomSchema = Schema({
name: {
type: String,
required: [true, 'Room name not provided']
},
deviceGroups: [{ type: Schema.Types.ObjectId, ref: 'DeviceGroup' }]
});
const deviceGroupSchema = Schema({
parentRoom: { type: Schema.Types.ObjectId, ref: 'Room' },
groupType: {
type: String,
enum: ['LIGHTS', 'BLINDS', 'ALARM_SENSORS', 'WEATHER_SENSORS']
},
devices: [{ type: Schema.Types.ObjectId, ref: 'Device' }]
});
// base schema for all devices
function DeviceSchema() {
Schema.apply(this, arguments);
// add common props for all devices
this.add({
name: String
});
}
util.inherits(DeviceSchema, Schema);
var deviceSchema = new DeviceSchema();
var lightBulbSchema = new DeviceSchema({
// add props specific to lightBulbs
isPoweredOn: Boolean,
currentColor: Number
});
var blindSchema = new DeviceSchema({
// add props specific to blinds
goingUp: Boolean,
goingDown: Boolean
});
var Room = mongoose.model("Room", roomSchema );
var DeviceGroup = mongoose.model("DeviceGroup", deviceGroupSchema );
var Device = mongoose.model("Device", deviceSchema );
var LightBulb = Device.discriminator("LightBulb", lightBulbSchema );
var Blind = Device.discriminator("Blind", blindSchema );
// this should return all devices
Device.find()
// this should return all devices that are LightBulbs
LightBulb.find()
// this should return all devices that are Blinds
Blind.find()
In the collection you will see __t property on each device
with values according to the schema used (LightBulb or Blind)
I haven't tried the code and i haven't used mongoose in a while but i hope it will work :)
Update - tested working example
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var util = require('util');
const roomSchema = Schema({
name: {
type: String,
required: [true, 'Room name not provided']
},
deviceGroups: [{ type: Schema.Types.ObjectId, ref: 'DeviceGroup' }]
});
const deviceGroupSchema = Schema({
parentRoomId: { type: Schema.Types.ObjectId, ref: 'Room' },
groupType: {
type: String,
enum: ['LIGHTS', 'BLINDS', 'ALARM_SENSORS', 'WEATHER_SENSORS']
},
devices: [{ type: Schema.Types.ObjectId, ref: 'Device' }]
});
// base schema for all devices
function DeviceSchema() {
Schema.apply(this, arguments);
// add common props for all devices
this.add({
name: String
});
}
util.inherits(DeviceSchema, Schema);
var deviceSchema = new DeviceSchema();
var lightBulbSchema = new DeviceSchema({
// add props specific to lightBulbs
isPoweredOn: Boolean,
currentColor: Number
});
var blindSchema = new DeviceSchema();
blindSchema.add({
// add props specific to blinds
goingUp: Boolean,
goingDown: Boolean
});
var Room = mongoose.model("Room", roomSchema );
var DeviceGroup = mongoose.model("DeviceGroup", deviceGroupSchema );
var Device = mongoose.model("Device", deviceSchema );
var LightBulb = Device.discriminator("LightBulb", lightBulbSchema );
var Blind = Device.discriminator("Blind", blindSchema );
var conn = mongoose.connect('mongodb://127.0.0.1/test', { useMongoClient: true });
conn.then(function(db){
var room = new Room({
name: 'Kitchen'
});
var devgroup = new DeviceGroup({
parentRoom: room._id,
groupType: 'LIGHTS'
});
var blind = new Blind({
name: 'blind1',
goingUp: false,
goingDown: true
});
blind.save();
var light = new LightBulb({
name: 'light1',
isPoweredOn: false,
currentColor: true
});
light.save();
devgroup.devices.push(blind._id);
devgroup.devices.push(light._id);
devgroup.save();
room.deviceGroups.push(devgroup._id);
room.save(function(err){
console.log(err);
});
// Room
// .find()
// .populate({
// path: 'deviceGroups',
// populate: {
// path: 'devices'
// }
// })
// .then(function(result){
// console.log(JSON.stringify(result, null, 4));
// });
}).catch(function(err){
});
Can you delete everything in you else statement and
console.log(room)
Check your mongo store to make sure you have data in your collection.

Inserting Object ID's into array in existing Mongoose schema with Node.js

I have an existing News articles section that I want to add categories to for more refined searching, my Schema's are as follows:
var ArticleSchema = new Schema({
title: String,
body: String,
author: {
type: Schema.Type.ObjectId,
ref: 'User',
required: true
},
image: String,
catagories: [{
type: Schema.Types.ObjectId, ref: 'Catagory'
}],
meta: {
created: {
type: Date,
'default': Date.now,
set: function(val) {
return undefined;
}
},
updated: {
type: Date,
'default': Date.now
}
}
});
ArticleSchema.statics.search = function (str, callback) {
var regexp = new RegExp(str, 'i');
return this.find({'$or': [{title: regexp}, {body: regexp}]}, callback);
};
module.exports = ArticleSchema;
var CatagorySchema = new mongoose.Schema({
name: { type: String, unique: true },
});
module.exports = CatagorySchema;
I want a user friendly input for selecting categories (don't even know what is best here, be it check-box's or a simple comma separated text input etc.). My question is what is the best practice for obtaining this kind of input and translating that into the Article Schema (providing the categories exist). If anyone could point me in the right direction it would be much appreciated. Thanks.
Keep the category names you want to search for in an array
{
categories: ["cat1", "cat2"]
}
then you can add an index to it and do a $in query. the current schema is not very good because you cannot look for the category in a single query but need to resolve all the "categories" links first.

Categories

Resources