Mongoose self nesting - node.js

I'd like to store the following:
var TestSchema = new Schema({
name: {
type: String
},
regions: [RegionSchema]
}
var RegionSchema = new Schema({
name: {
type: String
},
minX: {
type: Number
},
minY: {
type: Number
},
minZ: {
type: Number
},
maxX: {
type: Number
},
maxY: {
type: Number
},
maxZ: {
type: Number
},
children: [this]
});
So as you can see I'm trying to make a region object, able to contain region objects, however this fails to save without exception, presumably the [this] in the schema gets stuck in some endless loop or something.
How can I make this to work for nesting regions?
The json payload I could expect to send to this schema:
name: "test123",
regions: [
{
name: "TestRegion",
minX: 0,
minY: 0,
minZ: 0,
maxX: 100,
maxY: 255,
maxZ: 100,
children: [
{
name: "TestRegionChild",
minX: 3,
minY: 3,
minZ: 3,
maxX: 97,
maxY: 252,
maxZ: 97,
children: []
}
]
}
]
I appreciate any help, thank you.

If your other regions are saved first, you can save the children as a list of objectIds like this:
children: [{
type: Schema.ObjectId,
ref: 'Region'
}]
Another option is to redesign your Schema and have a 'parent' on your Region and delete the 'children' field. Then when you need to get all the children you can query easily and not have big nested objects.
var RegionSchema = new Schema({
--- other fields omitted ---
parent: {
type: Schema.ObjectId,
ref: 'Region'
}
});

Related

Get average rate for product comments in MongoDB and Express

I want to calculate average rating for products based on comments rate,
exactly I want to return products object with one more property in response when client call get all product api
my product schema is like below, thank you in advance.
const mongoose = require("mongoose");
const { s, rs, n, rn, ref, rref } = require("../utils/mongo");
let commentSchema = new mongoose.Schema(
{
user: rref("user"),
body: rs,
rate: {
...n,
default: 0,
enum: [0, 1, 2, 3, 4, 5],
},
},
{ timestamps: true }
);
let schema = new mongoose.Schema(
{
user: rref("user"),
name: rs,
description: s,
images: [s],
price: rn,
discount: n,
sizes: [sizeSchema],
categories: [ref("category")],
tags: [s],
comments: [commentSchema],
rating: n,
inStock: {
type: Boolean,
default: true,
},
stock: n,
sold: {
...n,
default: 0,
},
view: {
...n,
default: 0,
},
},
{ timestamps: true }
);
module.exports = mongoose.model("product", schema);
I want to return in response something like this:
let result = [
{
name: 'product name',
comments: [
{
user: "2a2sdw22das5262123223",
body: "good product",
rate: 4
},
{
user: "2a2sdw22das5262123223",
body: "good product",
rate: 2
}
],
avgRate: 2, // how to calculate this?
price: 20
...
}
]
You can use aggregation pipeline to do that, it will add the avgRating field avgRate which you can use for future ref:
db.collectionName.aggregate([{ $addFields : { avgRate: { $avg: "$comments.rate"} } }])

geo element must be an array or object: type: "Point"

When I tried post request like this
"{ "imgUrl": "Server\Pictures\i14182109167", "text": "Myself in
seoul", "tag": ["seoul", "tour"], "geometry" : {"type": "Point","coordinates": [80,
-27]} }"
The error causes
'Can\'t extract geo keys: { _id:
ObjectId(\'5b8e204455526366f86a6383\'), tag: [ "seoul", "tour" ],
date: new Date(1536041028423), imgUrl:
"Server\Pictures\i14182109167", text: "Myself in seoul", geometry: {
type: "Point", coordinates: [ 80, -27 ], _id:
ObjectId(\'5b8e204455526366f86a6384\') }, __v: 0 } geo element must
be an array or object: type: "Point"' }
even I added "type": "Point" in post request but, why?
const geoSchema = new Schema({
type: {
type: String,
default: 'Point',
index: '2dsphere'
},
coordinates: {
type: [Number]
}
});
const memoSchema = new Schema({
imgUrl: {
type: String
},
text: {
type: String
},
date: {
type: Date,
default: Date.now
},
tag: {
type: [String]
},
user: {
type: Schema.Types.ObjectId,
ref: 'Memo'
},
geometry: geoSchema
})
I experienced this error, tried several schema declarations, until I fixed by this implementing this design:
1. Create a new schema, which has Point as a property.
const mongoose = require('mongoose');
const {Point} = require('mongoose-geojson-schema');
const pointSchema = new mongoose.Schema({
type: {
type: String,
enum: ['Point'],
required: true
},
coordinates: {
type: [Number],
required: true
}
});
2. Schema for the object including above as a property:
const itemsSchema = new mongoose.Schema({
description: {
type: String,
required: true
},
location: {
type: pointSchema,
required: true
}
)
const Item = mongoose.model('Item', ItemsSchema);
module.exports = Item;
enter code here
3. Finally, my controller succesfully instantiates the object like this:
var geolocation =
{
type: 'Point',
coordinates: [
lng,
lat
]
};
const item = new Item({
description: req.body.description,
location: geolocation
})
Hope that helps.
I changed geometry to loc it worked!
but, I don't know why...
I was facing the same issue even after doing everything mention here. After spending too much time on this problem I get to know that if we save a default value it will work correctly.
Just follow the above answer and add
location: {
type: pointSchema,
default: {
type: 'Point',
coordinates: [0, 0],
},
required: false,
},
And delete the previous documents if any document has location.

Mongoose is saving only objectId instead of the whole object

I am trying to save array of objects, but it is just saving the ObjectIds instead of whole objects, even thought in schema there is no refference or something like that.
So, I have this schema:
let MatchPlayerSchema = new Schema({
deck: {type: Array, default: []}
});
And I am trying to save this array tooken from database (playerDeck):
[ { _id: 5a1fc7ee667b103aace5f3ec,
magicResist: 10,
armor: 10,
attack: 10,
health: 10,
name: 'Test',
__v: 0,
type: 'CardUnit' },
{ _id: 5a1fc7ee667b103aace5f3ec,
magicResist: 10,
armor: 10,
attack: 10,
health: 10,
name: 'Test',
__v: 0,
type: 'CardUnit' }]
Like this:
let player = new MatchPlayer();
player.deck = playerDeck;
player.save();
However, the result is:
"deck" : [
ObjectId("5a1fc7ee667b103aace5f3ec"),
ObjectId("5a1fc7ee667b103aace5f3ec")
]
I have tried to set deck to: [Schema.Types.Mixed], but it didnt not help either.
When I try to save something just like: ['test', 'test'], it saves alright.
I just can not figure out, what am I doing wrong.
Any ideas? Thank you
I had the same issue and setting the
mongoose.set('debug', true);
helped me to see what mongoose actually sending to the DB.
I was having in the Schema
const ChatSchema = mongoose.Schema({
messages: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Message',
}],
isRemoved: {
type: Boolean,
default: false,
required: true
}
});
After switching the type to mongoose.Schema.Types.Mixed it worked perfectly. This is how I was invoking an update
Chat.findOneAndUpdate({ _id: req.params.chatId }, { $push: { messages: message }},{new: true});
let MatchPlayerSchema = new Schema({
deck: {
type: Schema.Types.Mixed
}
});
You should be able to store an array of objects into 'deck'

Default values in array mongoose

I am trying to make default values for array in mogoose schema:
warning:
type: Array
default: [10, 50, 99]
Am I right in such decision or there is some other way to do this?
Regarding to the Mongoose-Documentation, your way is correct.
Here a small example:
var arrayTestSchema = new Schema({
anArray: {
type: Array,
'default': [1, 2, 3]
}
});
And a link to the related documentation page: http://mongoosejs.com/docs/2.7.x/docs/defaults.html
for Mongoose v5.x
If you want to specify the type of the array child, you can define it like example below:
const BlogSchema = new Schema({
tags: {
type: [String],
default: ["tech", "economy"],
},
})
or
const BlogSchema = new Schema({
tags: {
type: [
{
type: String,
// Another properties
},
],
default: ["tech", "economy"],
},
})
References:
https://mongoosejs.com/docs/schematypes.html#arrays
It should be a json, I don't know what is what you posted there.
new Schema({
warning: { type: Array, default: [10, 50, 99] }
})

How to save child Schema in mongodb using mongoose

Following is my order object that I am trying to save -
{
shipper:
{ firstName: 'Test ShipName',
address1: '10 Florida Ave',
phone1: '800-123-4567' },
consignee:
{ firstName: 'AAA Manufacturing',
address1: '100 Main Street' },
items:
[
{ length1: 45, weight1: 12, height1: 45, width1: 34 },
{ length2: 42, weight2: 34, height2: 90, width2: 54 }
]
}
On doing this -
Order(order).save(function(err, result){
if(err)
throw err;
console.log(result);
});
shipper, consignee are saving appropriate values but in database(mongodb), items are not saving properly -
"items" : [
{
"_id" : ObjectId("54e36e18c59700b513a5309d")
},
{
"_id" : ObjectId("54e36e18c59700b513a5309c")
}
],
Following is my oderSchema -
var orderSchema = mongoose.Schema ({
shipper: {type: addressSchema, 'Default':''}},
consignee: {type: addressSchema, 'Default':''} },
items: {type: [itemSchema], 'Default':''} },
});
Following is my itemSchema -
var itemSchema = mongoose.Schema({
length: {type: Number, required: false },
width: {type: Number, required: false },
height: {type: Number, required: false },
weight: {type: Number, required: false },
});
Let me know what I am doing wrong in saving the item info.
In your itemSchema, the properties are "length", "width" etc, however properties of the data that you're saving contains numbers at the end "length1", "length2", etc. You need to remove those numbers.

Resources