Is it expected behaviour of mongoose, or it shouldn't be like this. So I have 2 schema for users and address. The schema looks like these:
const addressSchema = {
addressLine: { type: String},
city: { type: String},
locations: { type: String, coordinates: [Number] }, <-- subdocument
}
const userSchema = {
name: { type: String },
email: { type: String },
addresses: {
primary: { type: AddressSchema },
others: { type: [AddressSchema] }
}
}
And I try to insert this data:
{
name: "John Doe",
addresses: {
primary: {
addressLine: "Apple Street"
},
others: [
{
addressLine: "Mango Street"
}
]
}
}
Now this is the confusing part. So I didn't include the locations in the input. But the data that saved in my DB looks like this:
{
name: "john Doe",
addresses: {
primary: {
addressLine: "Apple Street"
},
others: [
{
addressLine: "Mango Street",
locations: { <-- this locations suddenly shown!
coordinates: []
}
}
]
}
_id: randomString,
__v: 0
}
Please help, and thank you in advance :D
In this case, locations is automatically added in your subdocument because of coordinates field in it.
Whenever you define an array enter code heretype field in your schema, Mongoose automatically initialises it with empty array if the value is not provided.
And,since you are not passing any value to locations.coordinates, it is initializing it as an empty array.
If you want to test this theory, please remove coordinates from locations, and you will see the difference.
Related
I have some code in javascript with moongooes that I used in mongo DB to store a data
Sometimes I need to delete all the objects in array
and get a clean array
this is my schema
const orderSchema =new Schema({
date: {
type: Date,
},
OrderNumber: {
type: String,
required: true
},
City: {
type: String,
required: true
},
Address: {
type: String,
required: true
},
Phone: {
type: String
},
Country: {
type: String
},
Name: {
type: String,
required: true
},
Trackingnumber: {
type: String
},
ZipCode: {
type: Number
},
Province: {
type: String,
},
fulfillmentOrders:{
type: String,
},
Quantity: {
},
});
Holde:[
orderSchema
],
module.exports = mongoose.model('User', userSchema);
and my data on mongo looks like this
"Holde": [
{
"OrderNumber": "gid://shopify/Order/4958122475753",
"City": "xxxx",
"Address": "xxxx",
"Phone": "",
"Country": "xxx",
"Name": "xxx",
"Trackingnumber": "0",
"ZipCode": xxxx,
"fulfillmentOrders": "gid://shopify/FulfillmentOrder/6034089509097",
"Quantity": [
{
"quantity": 1,
"product": {
"id": "gid://shopify/Product/7909915590889"
},
"variant": {
"sku": "11111"
}
}
],
"_id": {
"$oid": "6389b12faaade0788141bf4f"
}
I try to delete all the objects in my array
whit this code
const User = require('../model/User');
const foundUse= await User.findOne({ "user":req.body.user}).exec();
await foundUse.updateOne({
Holde :{
$pull: {'_id':6389b12faaade0788141bf4f},
}
},
)
and expect to get "hold":[]
but actually
I get
"Holde": [
{
"_id": {
"$oid": "6389d882afbc458cc1c1af23"
}
}
],
It's pretty normal because you are updating your User with theses data.
With mongoose, the way to propperly delete item is .deleteMany(), but in your case it will only delete the User (and you seems to want to delete only the order).
You can then filter user's orders and re-assign it without the found order, using FindOneAndUpdate, like:
const User = require('../model/User');
const foundUser = await User.findOne({ "user": req.body.user });
const result = await User.updateOne({
Holde: foundUser?.Holde.filter(holde => holde._id !== HOLD_ID_TO_DELETE)
});
Where HOLD_ID_TO_DELETE is the id to delete (you seems to pass the whole user object with all orders at the moment)
But not it would be prettier and more maintenable to create an Order collection, linked to your User one using ref.
I have a collection called Orders that contains this schema:
const mongoose = require('mongoose');
const orderSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
},
restaurant: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Restaurant',
required: true
},
dishes: [
{
dish: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Dish'
},
amount: Number
}
],
price: {
type: Number,
required: true
},
comment: {
type: String,
required: false
},
status: {
type: String,
enum: ['PROCESSING', 'CANCELLED', 'COMPLETED', 'ERROR'],
default: 'PROCESSING'
},
timestamp: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Order', orderSchema);
Inside my router, I have this code:
let orders = await Order.find({restaurant: restaurantID, status:'PROCESSING'}).populate('dishes._id').exec()
Order.find does not throw an exception, but it isnt working either.
I want the res.body to look like this:
{
"_id": "objectID",
"user": "objectID",
"restaurant": "objectID",
"dishes": [
{
"amount": number,
"dish": {
//dish object
}
},
...
],
//other order properties
},
...
]
But for some reason the dishes array looks like this:
"dishes": [
{
"amount": 1,
"_id": "6184e848e6d1974a0569783d"
}
],
What am I doing wrong?
I know that if populate() worked the res.body dishes array would not have a property called 'dish' and instead have a property called _id that would contain the dish object, but this shouldnt be hard to change once populate() works.
EDIT:
I realised that my createOrder route could be part of the problem since it ignores my schema and uses an id property for the objectID instead of dish. The array I save to the DB contains a property called id for the id instead of dish, but shouldnt my schema throw an exception when i try to save something like this to my database?
At first glance, I think the problem might be that you have a syntax problem.
Try
.populate('dishes').exec()
instead of
.populate('dishes._id').exec()
I want to Query and array with regex inside and mongoose (mongoDB) model.
I want to search inside the nested array of the Productmodel :
const productSchema = new schema(
{
name: requiredString,
sku: requiredUniqueNumber,
ean: requiredUniqueNumber,
suppliers: [{ type: mongoose.Schema.Types.ObjectId, ref: SupplierModel }],
categories: [{ type: mongoose.Schema.Types.ObjectId, ref: CategoryModel }],
mainImage: requiredString,
images: [{ type: String }],
description: requiredString,
stock: requiredNumber,
price: requiredNumber,
totalOrders: requiredNumber,
reviews: [review],
},
{
timestamps: true,
count: true,
}
);
The model inside the "suppliers" array is:
const supplierSchema = new schema(
{
supplierName: requiredUniqueString,
invoiceAddress: address,
visitAddress: address,
status: supplierStatusEnum,
contacts: address,
accountType: accountTypeEnum,
logo: requiredString,
user: { type: schema.Types.ObjectId, ref: "products" },
},
{
timestamps: true,
}
);
Now here's the problem, if i query and and populate() i get all the results. But for some reason I cannot search inside the Array containing several suppliers. Here's of what i have:
foundProducts = await ProductModel.find({
$or: [
{
name: {
$regex: regex,
},
},
{
"suppliers.supplierName": {
$regex: regex,
},
},
{
description: {
$regex: regex,
},
},
],
});
The object in JSON:
If he finds that the suppliers model contains the regex he should give back the whole porductmodel containing that supplier.
What is the best way to search in all the items inside of an nested array.
ps. I'm a junior developer comming from PostgreSQL, so bare with me while I'm trying this noSQL "thing" :)
I was doing the wrong query. I need to do
{
"suppliers._id": {
$regex: regex,
},
},
I can only search on _id, since this is the way that i "modeled" it.
My problem is reading properties of nested object, which is inside other nested object.
GraphQL
type Mapping {
id: ID!
partnerSegmentId: ID!
ctSegmentId: CtSegment!
}
type PartnerSegment {
id: ID!
name: String!
platformId: Int!
partner: Partner!
}
type Partner {
id: ID!
name: String!
}
Once I try to query it like:
{
allMappings {
partnerSegmentId {
id
name
partner {
id
}
}
}
}
I recieve:
{
"data": {
"allMappings": [
null
]
},
"errors": [
{
"message": "Cannot return null for non-nullable field Partner.name.",
"locations": [
{
"line": 8,
"column": 9
}
],
"path": [
"allMappings",
0,
"partnerSegmentId",
"partner",
"name"
]
}
]
}
Mapping schema
const mappingSchema = new mongoose.Schema(
{
partnerSegmentId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'PartnerSegment',
required: [true, 'Mapping must have partner segment id.']
},
ctSegmentId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'CtSegment',
required: [true, 'Mapping must have CT segment id.']
}
},
{ timestamps: true }
);
I tried to read separately Partner, PartnerSegment and Mapping models. All works fine. Any idea where i should search source of the problem? I've checked mongodb docs and ids looks okay. I suppose it's fault of my model.
If you would like to take a closer look it's project repo.
SOLUTION:
Garbage Id in the return value was caused by not working populate in the nested entity. The way I managed to solve the problem:
const allMappings = () =>
Mapping.find({})
.populate('user')
.populate('ctSegment')
.populate({
path: 'partnerSegment',
populate: {
path: 'partner'
}
})
.exec();
In my novice skill to Mongodb and Mongoose, I seem to be failing miserably at this fundamental task.
I have a bounded array of 10 elements. A user can only have 10 pets, so I figured to make it bounded with set fields and empty values was the best way.
The pets array values are blank at the time of creation, because the user can add pets as they go along. When I look in mongo console, the pets array is unbounded with no fields. I also can't add values to the array.
Mongoose Schema:
var userSchema = new Schema({
firstName: { type: String, required: true },
lastName: { type: String, required: true },
username: { type: String, required: true, unique: true },
location: String,
created_at: Date,
pets: [
{ "pet0": {} },
{ "pet1": {} },
{ "pet2": {} },
{ "pet3": {} },
{ "pet4": {} },
{ "pet5": {} },
{ "pet6": {} },
{ "pet7": {} },
{ "pet8": {} },
{ "pet9": {} }
]
});
mongodb:
{ "_id" : ObjectId("56a3e324bdebcf801c1ca224"), "firstName" : "bob", "lastName" : "smith", "username" : "bob123", "pets" : [ ], "__v" : 0 }
When modifying the array:
UserModel.findOne({ firstName: "bob" }, 'pets', function(err, user) {
user.pets[0] = { "name": "felix", "type": "cat" }
user.save(function(err) { console.log(err); console.log('saved')});
});
output:
Mongoose: users.findOne({ firstName: 'bob' }) { fields: { pets: 1 } }
null
/home/one/github/foo/node_modules/mongoose/lib/schema/documentarray.js:100
doc.validate({ __noPromise: true }, function(err) {
^
TypeError: undefined is not a function
at /home/one/github/foo/node_modules/mongoose/lib/schema/documentarray.js:100:11
at DocumentArray.SchemaType.doValidate (/home/one/github/foo/node_modules/mongoose/lib/schematype.js:654:22)
at DocumentArray.doValidate (/home/one/github/foo/node_modules/mongoose/lib/schema/documentarray.js:78:35)
at /home/one/github/foo/node_modules/mongoose/lib/document.js:1156:9
at process._tickCallback (node.js:355:11)
MongoDB allows you to limit the number of elements in an array. This feature has also been implemented in Mongoose as part of an .update query. The steps for adding an element to an array and limiting its size are as follows:
Push the element(s) into the array.
Slice the array.
This snippet of code explains how to do this using Mongoose:
UserModel.findOne({ firstName: "bob" }, function(err, user) {
UserModel.update(user, {
$push: {
pets: {
$each: [{ name: "felix", type: "cat" }],
$slice: -10
}
}
}, function(err, numAffected) {
if (err) console.log(err);
console.log('updated');
});
});