Get only the length of mongoose virtual populate - database

I would like to know if there is a way in Mongoose of getting the number of matching localField/foreignField as virtual field, without retrieving all the documents through virtual population.
Example:
const ForumThreadSchema = new Schema({
code: { type: Number, required: true, unique: true },
title: { type: String, min: [10, 'Too short title'], max: [200, 'Too long title'], required: true },
description: { type: String, min: [10, 'Too short description'], max: [2000, 'Too long description'], required: true },
creation_date: { type: Date, default: Date.now, required: true },
updated_date: { type: Date, default: Date.now, required: true },
_authorId: { type: Schema.ObjectId, ref: 'User', required: true },
_forumId: { type: Schema.ObjectId, ref: 'Forum', required: true }
}, {
collection: 'ForumThreads',
toObject: { virtuals: true },
toJSON: { virtuals: true }
});
const ForumMessageSchema = new Schema({
code: { type: Number, required: true, unique: true },
content: { type: String, min: [10, 'Too short message content'], max: [2000, 'Too long message content'], required: true },
creation_date: { type: Date, default: Date.now, required: true },
update_date: { type: Date, default: Date.now, required: true },
_authorId: { type: Schema.ObjectId, ref: 'User', required: true },
_forumThreadId: { type: Schema.ObjectId, ref: 'ForumThread', required: true },
_parentMessageId: { type: Schema.ObjectId, ref: 'ForumMessage' }
}, {
collection: 'ForumMessages'
});
The virtual populate on the forum thread schema retrieves me all the message documents. I need a virtual field with only their number if possible.
ForumThreadSchema
.virtual('messages', {
ref: 'ForumMessage',
localField: '_id',
foreignField: '_forumThreadId'
});
ForumThreadSchema
.virtual('messages_count')
.get(function() {
return this.messages.length;
});
The second virtual only works if the population of the first one is done.
I also want to mantain the virtual populate but I would like to find a way of getting the number of matching documents without use it (in server APIs that not need all message documents but only their size).
Is it possible?

You just need to add the count option:
ForumThreadSchema
.virtual('messages_count', {
ref: 'ForumMessage',
localField: '_id',
foreignField: '_forumThreadId',
count: true
});
And then when you can populate just the count:
ForumThread.find({}).populate('messages_count')
Doc: https://mongoosejs.com/docs/populate.html#count

Related

model in mongodb user and product ref not working

my code does not working model of mongodb user and product ref does not work for me
and showing
error
Order validation failed: user: Path user is required., orderItems.0.product: Path product is required.
how can i solve it please help me
import mongoose from "mongoose";
const orderSchema = mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "User",
},
orderItems: [
{
name: { type: String, required: true },
qty: { type: Number, required: true },
image: { type: String, required: true },
price: { type: Number, required: true },
product: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "Product",
},
},
],
shippingAddress: {
address: { type: String, required: true },
city: { type: String, required: true },
postalCode: { type: String, required: true },
country: { type: String, required: true },
},
paymentMethod: {
type: String,
required: true,
},
paymentResult: {
id: { type: String },
status: { type: String },
update_time: { type: String },
email_address: { type: String },
},
taxPrice: {
type: Number,
required: true,
default: 0.0,
},
shippingPrice: {
type: Number,
required: true,
default: 0,
},
itemsPrice: {
type: Number,
required: true,
default: 0,
},
totalPrice: {
type: Number,
required: true,
default: 0,
},
isPaid: {
type: Boolean,
required: true,
default: false,
},
paidAt: {
type: Date,
},
isDelivered: {
type: Boolean,
required: true,
default: false,
},
deliveredAt: {
type: Date,
},
},
{
timestamps: true,
}
);
export const Order= mongoose.model("Order", orderSchema);
enter image description here

Advanced search with mongoose

I have an query object
const query = {
brand : BMW,
yearFrom : 2000,
yearTo : 2003,
price : 7000,
};
I am trying to find every BMW which is made between 2000 and 2003 included.
I am trying in this way but it doesn't work
if (query.yearFrom) {
return offerModel.find({query,year : {$gte : query.yearFrom }}, function(err,arr) {console.log(err,arr)}).skip(offset).limit(12);
}
Here's the mongoose schema
const mongoose = require('mongoose');
const offerSchema = new mongoose.Schema({
brand: {
type: String,
required: true,
},
model: {
type: String,
required: true,
},
year: {
type: Number,
required: true,
},
color: {
type: String,
required: true,
},
power: {
type: Number,
required: true,
},
mileage: {
type: Number,
required: true,
},
populatedState: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
condition : {
type: String,
required: true,
},
doors: {
type: Number,
required: true,
},
description: {
type: String,
required: true,
},
transmission: {
type: String,
required: true,
},
engineType: {
type: String,
required: true,
},
category: {
type: String,
required: true,
},
imageURLs : [],
imageIds : [],
creator: {
type: mongoose.Types.ObjectId,
ref: 'user'
},
})
module.exports = mongoose.model('offers', offerSchema);
Sample data from database
_id:60fe98301b76642e04a31c45,
imageURLs:[],
imageIds : [],
brand:BMW,
model:335,
year:2000,
color:White,
doors:4,
power:130
mileage:30000,
populatedState:Sofia,
price:7000,
condition:Used,
description:qweqweqweqe,
transmission:Automatic gearbox,
engineType:Petrol,
category:Sedan,
creator:60fe97d11b76642e04a31c44,
__v:0,
If i put only query it find brand,model and etc.But it doesn't get year search correctly.
I will be glad if you guys have some ideas how can i fix that
Thanks !
Try this
offerModel.find({
$and: [
{ brand :query.brand },
year : {
$gte: query.yearTo,
$lt: query.yearFrom
}
]
}, function (err, results) {
...
}

Mongoose: Find() return document with the the object that contains the value

I'm using MongoDB, and express.
I have a collection with all the countries, contains the states and cities.
Picture of a part of the collection
Now,
lets say I want to get all the cities that contains "Los" (like "San Antonio", "San Diego"),
when I'm using Find() - its return the all document with all the states and all the cities in the country (like in the picture above),
I want to return the all documents, but return only the objects that contains the value, inside array "cities"
Note: I expect to get different countries with cities that contains a part of the value in their names.
how to use the Find() to return as I want ?
hers is the schema I'm using:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CitiesSchema = new Schema({
capital:{
type: String,
required: true
},
currency:{
type: String,
required: true
},
emoji: {
type: String,
required: true
},
emojiU: {
type: String,
required: true
},
id: {
type: Number,
required: true
},
iso2: {
type: String,
required: true
},
iso3: {
type: String,
required: true
},
name: {
type: String,
required: true
},
native: {
type: String,
required: true
},
phone_code: {
type: String,
required: true
},
region: {
type: String,
required: true
},
states:
[{
cities:[{
id:{
type: Number,
required: true
},
latitude:{
type: String,
required: true
},
longitude:{
type: String,
required: true
},
name:{
type: String,
required: true
},
}],
id:{
type: Number,
required: true
},
name:{
type: String,
required: true
},
state_code:{
type: String,
required: true
},
}]
,
subregion: {
type: String,
required: true
}
});
const Cities = mongoose.model('Cities',CitiesSchema);
module.exports = Cities;
Edit: my Find() code:
Cities.find({"states.cities.name": city})
.then((data)=>{
return res.json(data);
})
lets say I want to search cities with the name "Los Santos". I want the result to be like this:
Picture of the result I expect to be return
instead, I'm getting the all states and cities in the countries - which I don't want.
UPDATE:
I found a way to return the data as I wish, by using aggregate with $unwind.
Cities.aggregate([{
$unwind: '$states'
},
{
$unwind: '$states.cities'
},
{
$match: {
'states.cities.name': {$regex: city, $options: "i"}
}
}
],
function (error, data) {
return res.json(data);
})
Try using RegEx, I use it while doing searches on MongoDB.
Cities.find({"states.cities.name": new RegExp(city)})
.then((data)=>{
return res.json(data);
})
I found a way to return the data as I wish, by using aggregate with $unwind.
Cities.aggregate([{
$unwind: '$states'
},
{
$unwind: '$states.cities'
},
{
$match: {
'states.cities.name': {$regex: city, $options: "i"}
}
}
],
function (error, data) {
return res.json(data);
})

Angular is not sending objects in objects

I'm sending this JSON with Angular.js to my node.js/express.js service:
{
"name": "MyGuitar",
"type": "electric",
"userid": "123",
"likes": 0,
"dislike": 0,
"guitarParts": {
"body": {
"material": "/content/img/hout.jpg",
"_id": "5566d6af274e63cf4f790858",
"color": "#921d1d"
},
"head": {
},
"neck": {
"material": "/content/img/hout.jpg",
"_id": "556d9beed90b983527c684be",
"color": "#46921d"
},
"frets": {
},
"pickup": {
},
"bridge": {
},
"buttons": {
}
}
}
The guitarParts are not saved in the MongoDB database.
Mongoose inserts the following:
Mongoose: guitars.insert({ name: 'MyGuitar', type: 'electric', userid: '123', likes: 0, _id: ObjectId("557023af9b321b541d4d416e"), guitarParts: [], __v: 0})
This is my Mongoose model:
guitarPart = new Schema({
id: { type: String, required: true },
color: { type: String, required: true },
material: { type: String, required: true },
x: { type: Number, required: false },
y: { type: Number, required: false },
width: { type: Number, required: false },
height: { type: Number, required: false},
});
guitarParts = new Schema({
body: [guitarPart],
neck: [guitarPart],
head: [guitarPart],
bridge: [guitarPart],
frets: [guitarPart],
pickup: [guitarPart],
buttons: [guitarPart]
});
guitar = new Schema({
name: { type: String, required: true, unique: false },
type: { type: String, required: true },
userid: { type: String },
likes: { type: Number },
dislikes: { type: Number },
guitarParts: [guitarParts],
kidsguitar: { type: Boolean },
lefthanded: { type: Boolean },
assemblykit: { type: Boolean }
},
{
collection: 'guitars'
});
I don't know what's going wrong. Any ideas?
According to the mongoose documentation of Subdocuments says: Sub-documents are docs with schemas of their own which are elements of a parents document array
And in your schema you provided: guitarParts is not an array, it is an object and a guitarPart is not array it is an object too. So that's why it is not saving.
So the correct way to model your Schema it would be:
var guitarDefinition = {
_id: {type: String, required: true},
color: {type: String, required: true},
material: {type: String, required: true},
x: Number,
y: Number,
width: Number,
heigth: Number
};
var guitarSchema = Schema({
name: { type: String, required: true, unique: false },
type: { type: String, required: true },
userid: String,
likes: Number,
dislikes: Number ,
kidsguitar: Boolean,
lefthanded: Boolean ,
assemblykit: Boolean,
guitarParts: {
body: guitarDefinition,
neck: guitarDefinition,
head: guitarDefinition,
bridge: guitarDefinition,
frets: guitarDefinition,
pickup: guitarDefinition,
buttons: guitarDefinition
}
});
Actually I have run in my computer and it is saving you can see my complete code here: https://gist.github.com/wilsonbalderrama/f10c38f9fb510865edc2

mongodb User with subdocument vs document with UserId

I am using meanjs and I would like to store some user data in a one to many relationship. My case is similar to the articles example but the articles will only ever be accessed through the user. I want the route to be something like
Users/:userId/articles
or
Users/me/articles
Question 1
Should I just stick with the articles model as it is or should I make articles a subdocument of user. e.g.
var UserSchema = new Schema({
firstName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
type: String,
trim: true
},
email: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your email'],
match: [/.+\#.+\..+/, 'Please fill a valid email address']
},
username: {
type: String,
unique: 'testing error message',
required: 'Please fill in a username',
trim: true
},
articles: [articleModel.schema],
password: {
type: String,
default: '',
validate: [validateLocalStrategyPassword, 'Password should be longer']
},
salt: {
type: String
},
provider: {
type: String,
required: 'Provider is required'
},
providerData: {},
additionalProvidersData: {},
roles: {
type: [{
type: String,
enum: ['user', 'store', 'admin']
}],
default: ['user']
},
updated: {
type: Date
},
created: {
type: Date,
default: Date.now
},
/* For reset password */
resetPasswordToken: {
type: String
},
resetPasswordExpires: {
type: Date
}
});
Question 2 if I make it a subdocument can I still use the $resource function or do I have to make custom functions?
The maximum BSON document size is 16 megabytes. The maximum document size helps ensure that a single document cannot use excessive amount of RAM or, during transmission, excessive amount of bandwidth. To store documents larger than the maximum size, MongoDB provides the GridFS API.

Resources