Find nested array elements - node.js

This is my schema:
Appliance = new Schema({
appliance_name: {type:String},
appliance_id: {type:String},
appliance_description: {type:String},
keywords: [{ type: String}],
appliance_type: { type: String},
appliance_status: { light: { write_state: Number, read_state: Number },
fan: {write_state: Number, read_state: Number, write_speed: Number, read_speed: Number}
}
});
Room= new Schema({
name: {type: String, required:true},
device_auth_code: {type: String},
alt_name: {type:String},
keywords: [{type: String}],
appliance: [Appliance]
});
Home = new Schema({
name: { type: String, required: true},
description: {type: String},
administrator: {type : mongoose.Schema.Types.ObjectId, ref: 'User', required: true},
users: [{
_id: {type : mongoose.Schema.Types.ObjectId, ref: 'User'},
email: {type: String},
name: { type: String},
status: { type: Number}
}],
rooms: [Room]
});
And here is the typical home.
"type": true,
"code": "GET_SUCCESS",
"homes": {
"_id": "58760ff6045e332b81449b42",
"description": "",
"administrator": "586df1e06485de5fc48b72a5",
"name": "CM",
"__v": 9,
"rooms": [
{
"name": "RK",
"alt_name": "RKa",
"_id": "58775437234451346ce3d967",
"appliance": [
{
"_id": "5877546f234451346ce3d968",
"appliance_type": "Light",
"appliance_name": "TubeLights",
"keywords": []
}
],
"keywords": []
}
],
"users": []
}
}
Home has nested array of rooms and each room has nested array of appliances.
Home.findOne({'room.appliance._id': appliance_id}) would return the whole document. The $ operator wouldn't work I would have to imagine.
Is it possible to receive that particular appliance or the whole document with that particular room and appliance only being returned?
How do I find a particular appliance and return that appliance?

Here you've used mongoose subdocs architecture in your home schema definition. So you could retrieve any particular room:
Home.findById(home_id, function(err, home){
var room = home.rooms.id(room_id);
res.json(room)
});
or a particular appliance:
Home.findById(home_id, function(err, home){
var room = home.rooms.id(room_id);
var appliance = room.appliance.id(appliance_id);
res.json(appliance)
});

Related

Mongoose: Populate an array of related values

I'm fairly new to Mongo and Mongoose, so if this question is rather silly then feel free to point me in the right direction.
I have a API with models for users and stories that they published. When I display the users, I want the stories to show as well.
The relation is drawn rather simply:
const userSchema = mongoose.Schema({
username: {
type: String,
unique: true,
},
password: String,
firstName: {
type: String,
required: false,
},
lastName: {
type: String,
required: false,
},
birthday: {
type: Date,
},
bio: {
type: String,
required: false,
},
country: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Country',
},
stories: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Story',
}]
})
With a stories scheme declared as such:
const storySchema = new mongoose.Schema({
name: {
type: String,
max: 255,
},
url: {
type: String,
unique: true,
},
description: {
type: String,
required: false,
},
length: {
type: Number,
default: 0,
},
createdAt: Date,
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
language: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Country'
},
type: {
type: mongoose.Schema.Types.ObjectId,
ref: 'StoryType'
},
genre: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Genre'
},
})
I print the values using the simple find method (the action for now is only meant to show all of them.
app.get('/list-users', async (req, res) => {
const users = await User.find().populate('country').populate('stories').exec();
res.json(users);
});
Unfortunately, although the results show all the values properly, the stories array does not get populated at all.
[
{
"_id": "6127ce5b0576979256fd3e08",
"username": "test",
"password": "123",
"firstName": "tst",
"lastName": "tst",
"birthday": "1995-11-02T00:00:00.000Z",
"country": {
"_id": "6127c020f95eb5abf72f713a",
"name": "Poland",
"languange": "Polish",
"__v": 0
},
"stories": [],
"__v": 0
}
]
The docs have a clear indicator that such schemas will return an empty array, and I am aware I could just run a find by User and populate with that but I'm wondering what is the cleanest solution to apply in a situation like this.
Any help would be of great value.

Building Mongoose models for an Express Nodejs API with refpath

I'm new to building rest api's with mongoose and express and have a question on how to use refPath correctly on my Models files and allowing for an array of items.
Below I have included the code for a model (built thus far) and would love any input on if I'm even close to building this correctly.
I will also include a screenshot that visually depicts the relationships I'm trying to create.
Those who answer questions here are GODS and I appreciate all the help this community has given me over the years!
const mongoose = require("mongoose");
const slugify = require("slugify");
const AlertSchema = new mongoose.Schema({
parentId: {
type: mongoose.Schema.ObjectId,
required: true,
refPath: "parentModel",
},
parentModel: {
type: String,
required: true,
enum: ["orgs", "clients"],
},
status: { type: String, default: "no-status" },
departments: [{ type: mongoose.Schema.Types.ObjectId, ref: "orgs" }],
createdAt: { type: Date, default: Date.now },
createdByType: [{ type: mongoose.Schema.Types.ObjectId, ref: "users" }],
createdById: [{ type: mongoose.Schema.Types.ObjectId, ref: "users" }],
groups: [{ type: String, default: "unGrouped" }],
stage: [{ type: mongoose.Schema.Types.ObjectId, ref: "stages" }],
children: { type: String },
resource: {
type: String,
match: [
/https?:\/\/(www\.)?[-a-zA-Z0-9#:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()#:%_\+.~#?&//=]*)/,
"Please use a valid URL with HTTP or HTTPS",
],
},
notes: [{ type: mongoose.Schema.Types.ObjectId, ref: "notes" }],
comments: [{ type: mongoose.Schema.Types.ObjectId, ref: "comments" }],
priority: { type: String },
assignedTo: [{ type: mongoose.Schema.Types.ObjectId, ref: "users" }],
title: {
type: String,
required: [true, "Please add a title"],
maxlength: [50, "Title cannot be more than 50 characters"],
},
message: {
type: String,
required: [true, "Please add a message"],
maxlength: [500, "Message cannot be more than 500 characters"],
},
slug: String,
});
//create alert slug from the title
AlertSchema.pre("save", function (next) {
console.log("Slugify Ran", this.name);
this.slug = slugify(this.title, { lower: true });
next();
});
module.exports = mongoose.model("Testalert", AlertSchema);
Desired relationships diagram:

Populate Virtuals - populate the existing array its referencing .

Is it possible to use mongoose's Populate Virtuals to populate the array of values it is referencing?
User Model
var userSchema = new mongoose.Schema({
auth_key: {type: String},
channels: [{
name: {type: String},
last_access: { type: Date, default: Date.now },
status: {type: String, default: false },
new_messages: {type: Number},
user_channel_group: {type: String}
}]
}, {
toJSON: {
virtuals: true
}
});
userSchema.virtual('channels.details', {
ref: 'channel',
localField: 'channels.name',
foreignField: 'name'
});
var user = mongoose.model('user', userSchema, 'user');
Channel Model
var channelSchema = new mongoose.Schema({
name: {type: String, required: true},
members: [{ type: String, required: true }],
displayName: {type: String},
type: {type: Number},
create_at: {type: Date, default: Date.now}
});
var channel = mongoose.model('channel', channelSchema, 'channel');
My query that I am using I want the virtual to present the channel details from each channel alongside the channels a user is subscribed to. so something like this..
[{
"_id": "588a82ff7fe89686fd2210b0",
"channels": [{
"details": {
"_id": "588a80fd7fe89686fd2210a8",
"name": "channel1",
"members": []
},
"name": "channel1"
}, {
"details": {
"_id": "588a80fd7fe89686fd2210a9",
"name": "channel2",
"members": []
},
"name": "channel2"
}],
"id": "588a82ff7fe89686fd2210b0"
}
...
]
My Query for this is ..
user.find({}).populate('channels.details').exec()

How sum each values of relationship objectId with mongoose

i want to sum each values of ObjectId field in relationship with moongose..
I have this:
`var wineSchema = new Schema({
name: { type: String },
code: { type:String},
type: {
type: String,
enum: ['Red','Rose','White']
},
winery: { type: String },
grape_type: { type: String },
year: { type: Number },
alcohol: { type: Number },
rates: [{ type: Schema.ObjectId, ref: "Rate" }],
Comments: [{ type: Schema.ObjectId, ref: "Comment" }],
});`
And this:
`var rate = new Schema({
user : { type: Schema.ObjectId, ref: "User" },
userName : {type: String},
wineName : { type: String},
rating : { type: Number}
});`
I want sum total values of each rate.rating inside wineSchema.rates..
How can I do it?

Mongoose returns null array when populate

I'm trying to create a webapp with mongoose and nodejs. This is the first time i'm using mongoose and nodejs so i'm not quit good at it.
I have a person model:
var PERSON = new mongoose.Schema({
name: {type: String, required: true},
zipcode: {type: String, required: true},
city: {type: String, required: true},
street: {type: String, required: true},
address: {type: Number, required: true},
email: {type: String, required: true},
type: {type: String, enum: ['lid', 'passant'], required: true},
ships: {
type: [{
name: {type: String, required: true},
length: {type: Number, required: true},
type: {type: String, required: true},
picture: {type: Buffer, required: false}
}],
required: false
},
user: {
type: {
userName: {type: String, required: true},
password: {type: String, required: true},
passwordKey: {type: String, required: true},
roles: {type: [{type: mongoose.Schema.Types.ObjectId, ref: 'role'}], required: true}
},
required: false
}
},
{
collection: 'PERSON'
});
And the rol model:
var ROLE = new mongoose.Schema({
name: {type: String, required: true}
},
{
collection: 'ROLE'
});
When i'm trying to run a find query on the person model, I want to populate the user.roles array. But as a result it remains empty.
/ GET a specific person by id or type/
server.get('/api/person/:id', function (req, res, next) {
if (helper.isValidObjectID(req.params.id)) {
person.findById(req.params.id).populate("user.roles").exec(function (err, result) {
if (err) {
res.status(404).json(err);
} else {
res.status(200).json(result);
}
}
);
} else {
next();
}
}, function (req, res, next) {
person.find({type: req.params.id}).populate('user.roles').exec(function (err, result) {
if (err) {
res.status(404).json(err);
} else {
res.status(200).json(result);
}
});
});
and as a result i get:
{
"_id":"553f79d4f1481c0c14b42d59",
"name":"Wilco Boogert",
"zipcode":"4305RH",
"city":"Ouwerkerk",
"street":"baalpapenweg",
"address":2,
"email":"wilcoboogert17#gmail.com",
"type":"lid",
"user":{
"userName":"wboogert",
"password":"sha1$168fd599$1$502b965cb083ebdfcafb17e655455ef63779e1a1",
"passwordkey":"kfjvlksdfm",
"roles":[
]
},
"__v":0,
"ships":[
{
"name":"titanic",
"length":269,
"type":"Olympic-klasse",
"_id":"553f79d4f1481c0c14b42d5a"
}
]
}
The orginal object in the database is:
{
"_id": {
"$oid": "553f79d4f1481c0c14b42d59"
},
"name": "Wilco Boogert",
"zipcode": "4305RH",
"city": "Ouwerkerk",
"street": "baalpapenweg",
"address": 2,
"email": "wilcoboogert17#gmail.com",
"type": "lid",
"user": {
"roles": [
{
"$oid": "5522996f0fff331ed03cae6c"
}
],
"passwordkey": "kfjvlksdfm",
"password": "sha1$168fd599$1$502b965cb083ebdfcafb17e655455ef63779e1a1",
"userName": "wboogert"
},
"ships": [
{
"name": "titanic",
"length": 269,
"type": "Olympic-klasse",
"picture": "<Binary Data>",
"_id": {
"$oid": "553f79d4f1481c0c14b42d5a"
}
}
],
"__v": 0
}
so as you an see the roles is empty. And I search the web but i cannot find what the problem is. Can annyone help me?
You should replace this line :
roles: {type: [{type: mongoose.Schema.Types.ObjectId, ref: 'role'}], required: true}
with this one :
roles: {type: [{type: mongoose.Schema.Types.ObjectId, ref: 'ROLE'}], required: true}
In fact, the reference must be the exact same name as it's defined :
collection: 'ROLE'
It's case sensitive.

Resources