Mongoose Subdocument for Geojson - node.js

I am not able to define a correct reusable Point Schema. I just copied the example schema in https://mongoosejs.com/docs/geojson.html
This is the error I'm encountering when starting the node.js app
/home/******/projects/realista-api/node_modules/mongoose/lib/schema.js:418
throw new TypeError('Invalid value for schema path ' + prefix + key + '');
^
TypeError: Invalid value for schema path coordinates
I already tried using a non-reusable schema. By directly defining it at the parent schema and it works
coordinates: {
type: {
type: String,
enum: ['Point'],
required: true
},
coordinates: {
type: [Number],
required: true
}
},
Here is the code
import { Schema, Document } from 'mongoose';
interface Point extends Document {
type: string,
coordinates: Array<number>,
}
const PointSchema: Schema = new Schema({
type: {
type: String,
enum: ['Point'],
required: true
},
coordinates: {
type: [Number],
required: true
}
}, {
id: false
});
export {
Point,
PointSchema,
}
I'm using that as subdocument in another schema
const ProjectSchema: Schema = new Schema({
owner: {
type: Schema.Types.ObjectId,
ref: 'User',
required: false,
},
logo: {
type: String,
required: false,
},
name: {
type: String,
required: true,
},
location: {
type: String,
required: false,
},
suburb: {
type: String,
required: false,
},
stateCode: {
type: String,
required: false,
},
country: {
type: String,
required: false,
},
countryName: {
type: String,
required: false,
unique: true,
sparse: true,
},
coordinates: PointSchema,// this is the field in question
commission: {
type: Schema.Types.Decimal128,
required: false,
},
tax: {
type: Schema.Types.Decimal128,
required: false,
},
propertyType: {
type: Schema.Types.ObjectId,
ref: 'PropertyType',
required: true,
},
address: {
type: String,
required: false,
},
title: {
type: String,
required: false,
},
description: {
type: String,
required: false,
},
videoTour: {
type: String,
required: false,
},
matterPortUrl: {
type: String,
required: false,
},
currency: {
type: String,
required: false,
},
minPrice: {
type: Schema.Types.Decimal128,
required: false,
},
maxPrice: {
type: Schema.Types.Decimal128,
required: false,
},
otherPrice: {
type: String,
required: false,
},
featureLandSizeMin: {
type: String,
required: false,
},
featureLandSizeMax: {
type: String,
required: false,
},
featureLandSizeUnit: {
type: String,
required: false,
},
featureBuiltStart: {
type: Date,
required: false,
},
featureBuiltEnd: {
type: Date,
required: false,
},
featureNumOfLevel: {
type: Number,
required: false,
},
featureNumOfUnit: {
type: Number,
required: false,
},
featureFlooring: {
type: String,
required: false,
},
featureExterior: {
type: String,
required: false,
},
featureConcierge: {
type: String,
required: false,
},
indoorFeatures: {
type: String,
required: false,
},
outdoorFeatures: {
type: String,
required: false,
},
minBedrooms: {
type: Number,
required: false,
},
maxBedrooms: {
type: Number,
required: false,
},
minBathrooms: {
type: Schema.Types.Decimal128,
required: false,
},
maxBathrooms: {
type: Schema.Types.Decimal128,
required: false,
},
minParking: {
type: Number,
required: false,
},
maxParking: {
type: Number,
required: false,
},
csvVariationPending: {
type: Boolean,
required: false,
default: false,
},
isPrivate: {
type: Boolean,
required: false,
default: false,
},
status: {
type: Boolean,
required: false,
default: false,
},
variations: [{
type: Schema.Types.ObjectId,
ref: 'ProjectVariation',
}],
deletedAt: {
type: Date,
required: false,
}
}, {
collection: 'projects',
timestamps: true,
strict: false,
});
What am I doing wrong? Thanks in advance.

Was able to make it work. Hope this helps others who are developing using node.js
The issue was caused by 2 things:
Mongoose, when declaring subdocuments (nested objects or array of objects), gets confused when there is a type field in the document since in Mongoose concept, it is a reserved word for declaring the type of field. In my case, the type key comes from GeoJSON since it is required by MongoDB to be in that format. Here is a link from mongoose docs for better understanding.
What I just did is change PointSchema to this
import { Schema, Document } from 'mongoose';
interface Point extends Document {
type: string,
coordinates: Array<number>,
}
const PointSchema: Schema = new Schema({
type: {
$type: String,
enum: ['Point'],
required: true
},
coordinates: {
$type: [Number],
required: true
}
}, {
_id: false,
typeKey: '$type',
});
export {
Point,
PointSchema,
}
I'm also having a problem w/ circular dependency in node.js when importing/requiring the PointSchema. This error
/home/******/projects/realista-api/node_modules/mongoose/lib/schema.js:418 throw new TypeError('Invalid value for schema path ' + prefix + key + ''); ^ TypeError: Invalid value for schema path coordinates
occurred because PointSchema is undefined when I'm using it in ProjectSchema.
W/c justifies why issues in Mongoose Github suggest that mostly when they encounter that error, it is because of misspelled types (ObjectID instead of ObjectId), or in my case undefined w/c is invalid type.

Related

MongoDB schema validation with nested array or object in strict mode

i have schema which is nested
so need to validate whole schema, like if it has an extra attributes then throw error
i have tried with strict: 'throw' but that work only for main attributes, not for nested attributes.
const { Schema } = mongoose;
const DatasourceSchema = new Schema({
id: {
type: String,
unique: true,
required: true,
},
display_name: {
type: String,
required: true,
maxlength: 125
},
contact_info: {
type: Schema({
website: {
type: String,
required: false
},
registrar_phone: { type: String },
registrar_email: { type: String },
addresses: [{
type: Schema({
addr1: { type: String, required: false },
addr2: { type: String, required: false },
country: {
name: { type: String, required: true },
a2_code: { type: String, required: true },
}
}),
required: false
}]
}),
required: true,
}
},
{
strict: 'throw',
useNestedStrict: true
});
what i need is if i add any extra KEY (attributes) in object or array at any level that will throw errors

React mongoose validation failed

I am trying to store order data but getting following error when adding it to mongoose:
Request:
Response:
Here is my source Code:
placeOrder Handler:
const placeOrderHandler = () => {
dispatch(
createOrder({
orderItems: cartItems,
shippingAddress: {
address: shippingAddress.address,
city: shippingAddress.city,
postalCode: shippingAddress.postalCode,
country: shippingAddress.country,
},
paymentMethod: paymentMethod,
itemPrice: cart.itemPrice,
shippingPrice: cart.shippingPrice,
taxPrice: cart.taxPrice,
totalPrice: cart.totalPrice,
})
);
};
orderModel.js
const mongoose = require("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.0,
},
totalPrice: {
type: Number,
required: true,
default: 0.0,
},
isPaid: {
type: Boolean,
required: true,
default: false,
},
paidAt: {
type: Date,
},
isDelivered: {
type: Boolean,
required: true,
default: false,
},
deliveredAt: {
type: Date,
},
},
{
timestamps: true,
}
);
const Order = mongoose.model("Order", orderSchema);
module.exports = Order;
If I am not wrong it is throwing error on orderItems:, but I am sending array of objects data which I have already defined in my orderModel.js.
As #Ernesto mentioned I was writing product in my schema instead of productID. Here is the correct way:
orderItems: [
{
name: { type: String, required: true },
qty: { type: Number, required: true },
image: { type: String, required: true },
price: { type: Number, required: true },
productID: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Product',
},
},
],

Model.find is not a function mongoose

I have a mini casino game and have a mongoose model defined as following:
const jackpotSchema = mongoose.Schema({
round_id: {
type: String,
default: uniqid(),
required: true,
},
createdAt: {
type: Date,
required: true,
default: Date.now
},
closedAt: {
type: Date,
},
startedAt: {
type: Number,
},
roundSecret: {
type: String,
required: true,
},
random_org_hash: {
type: String,
},
random_org_obj: {
type: String
},
roundSecretHash: {
type: String,
},
winningPercentage: {
type: Number,
// required: true,
// first 5 characters of the secret hash, converted into decimal then divided by 10K
},
publicHash: {
type: String,
required: true,
// SHA-256 roundSecret + winningPercentage
},
finalHash: {
type: String,
},
winningTicket: {
type: Number,
},
winningDepositIndex: {
type: Number,
},
deposits: [{
uid: {
type: String,
required: true,
},
user: {
type: String,
required: true,
},
nonce: {
type: Number,
},
amount: {
type: Number,
required: true,
},
user_avatar: {
type: String,
},
ticketRangeMin: {
type: Number,
required: true,
},
ticketRangeMax: {
type: Number,
required: true,
},
referral: {type: String},
timestamp: {type: Date},
timestamp_readable: {type: String}
}],
total: {
type: Number,
required: true,
default: 0,
},
totalTickets: {
type: Number,
default: 0,
},
winner: {
type: String,
default: "",
},
winner_avatar: {
type: String,
},
active: {
type: Boolean,
default: true,
required: true,
},
open: {
type: Boolean,
required: true,
default: true,
},
roundTime: {
type: Number,
// default: potConfig.potLength,
default: 20000,
},
success: {
type: Boolean,
},
fee: {
type: Number,
default: potConfig.potFee,
}
})
module.exports = mongoose.model("Jackpot", jackpotSchema)
When running my app locally, I experience no errors.
However when running on a ubuntu production environment, I get the following error:
Jackpot.find is not a function
The stack trace says that the error is coming from db_utils.js
which looks like the following:
const Jackpot = require("./models/Jackpot");
...
async retrieveStats () {
var jackpots = await Jackpot.find().lean();
}
I have checked to see whether my module.exports was defined correctly, and it is. Not sure why this error is happening.
My local and production node versions match.
12.18.4
Don't you need to do
const jackpotSchema = new mongoose.Schema({...})
instead of
const jackpotSchema = mongoose.Schema({...})

creating an attribute that contains a list of objects node js

Im new using node js , what im trying to do is creating an attribute that contains a list of projects in the userSchema so i can display the projects when the user log in in my electron app
this is my userschema :
var UserSchema = new Schema(
{
username: {
type: String,
unique: true,
required: true,
},
password: {
type: String,
required: true,
},
email: {
type: String,
unique: true,
required: true,
},
nom: {
type: String,
required: true,
},
prenom: {
type: String,
required: true,
},
verif_code: {
type: String,
required: false,
},
}, { timestamps: { createdAt: 'created_at' } });
and this is my projectSchema :
var ProjectSchema = new Schema(
{
description: {
type: String,
},
useremail: {
type: String,
},
imageurl: {
type: String,
},
var UserSchema = new Schema(
{
username: {
type: String,
unique: true,
required: true,
},
password: {
type: String,
required: true,
},
email: {
type: String,
unique: true,
required: true,
},
nom: {
type: String,
required: true,
},
prenom: {
type: String,
required: true,
},
verif_code: {
type: String,
required: false,
},
projects: [{type: Types.ObjectId, ref: 'projects'}],//projects is name of table in database
}, { timestamps: { createdAt: 'created_at' } });

Mongoose/MongoDB Empty SubSchema Array

I have a model in Mongoose that looks like this:
const orderLogSchema = mongoose.Schema(
{
removed: { type: String, required: true },
},
{
timestamps: true,
}
)
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.0
},
totalPrice: {
type: Number,
required: true,
default: 0.0
},
isPaid: {
type: Boolean,
required: true,
default: false
},
paidAt: {
type: Date,
},
isDelivered: {
type: Boolean,
required: true,
default: false
},
deliveredAt: {
type: Date,
},
couponCode: {
type: Object,
required: false
},
orderVerifyLog: [orderLogSchema],
}, {
timestamps: true
})
I need to be able to empty out the orderVerifyLog which is populated with the orderLogSchema. I have tried a bunch of things most recently I pulled the order into a variable, and I am able to access orderVerifyLog by using order.orderVerifyLog but I cant figure out how to empty out that orderLogSchema. I tried:
order.orderVerifyLog = []
order.save()
Is there an easy way to work with that "sub" schema and zero it out?
Basically I am pulling the log items from that schema for an order and displaying them on my front-end. Then I was to fire off an action to clears it out so they don't display every time the order is loaded (Only want them to show once). I also tired to loop over each item in the orderVerifyLog and use pull to remove them, but for some reason it always leaves one in there.

Resources