passing nested JSON data from mongoose model is not working - javascript

I am pushing nested JSON data to database. This is how my schema looks like,
const mongoose = require('mongoose');
// original Schema
const dataSourceSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true, unique: true },
type: { type: String, required: true },
projectId: { type: mongoose.Schema.Types.ObjectId, ref: 'Project', required: true },
config:{type: String, required: true}
});
module.exports = mongoose.model('DataSource', dataSourceSchema);
I would like to pass the following json data to my dataSourceSchema,
{
“name”:”JdbcSourceConnector”,
"type" :"string",
“config”: {
“connector.class”:” io.confluent.connect.jdbc.JdbcSourceConnector”,
“tasks.max”:1,
“connection.url”:”<connection to connect to database along with username and password>”,
“mode”:”incrementing”,
“incrementing.column.name”:”<incrementing column name in table>”,
“topic.prefix”:”test-mysql-jdbc-”
}
}
But its not taking, gives casting error or ',' expected.
So i tried this,
const dataSourceSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true, unique: true },
type: { type: String, required: true },
projectId: { type: mongoose.Schema.Types.ObjectId, ref: 'Project', required: true },
config:{
connector.class:{ type: String, required: true },
tasks.max:{ type: String, required: true },
connection.url:{ type: String, required: true },
mode:{ type: String, required: true },
incrementing.column.name:{ type: String, required: true },
topic.prefix:{ type: String, required: true }
}
});
this Schema is also giving me errors, ',' expected.
If i pass just a string as i have mentioned in my original schema, the data gets stored in db.
but i want to pass the nested json data, please guide me in right direction.
I also tried stringify the data , its not working.

As I see it , the error lies in defining you schema with your second schema you came close to the answer. Change you schema as follows:
const dataSourceSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true, unique: true },
type: { type: String, required: true },
projectId: { type: mongoose.Schema.Types.ObjectId, ref: 'Project', required: true },
config:{
connectorClass:{ type: String, required: true },
tasksMax:{ type: String, required: true },
connectionUrl:{ type: String, required: true },
mode:{ type: String, required: true },
incrementingColumnName:{ type: String, required: true },
topicPrefix:{ type: String, required: true }
}
});
I have suggested the change as mongoose doesn't understand the dot notation in the key column of it's schema, hence you were receiving the error you have mentioned.
If you want to use the dot notation for some reason encapsulate the key in " and not in the special character as appearing in your code snippet.
P.s. - Don't forget to change the key names in your json

Related

What is the difference between surrounding the type with square brackets and surrounding the whole object

What is the difference between this code:
const userSchema = new Schema(
{
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
phoneNumber: { type: Number, required: false, unique: true },
address: [{ type: mongoose.Types.ObjectID, required: true, ref: "Address" }],
},
{
timestamps: true,
}
);
And this code:
const userSchema = new Schema(
{
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
phoneNumber: { type: Number, required: false, unique: true },
address: { type: [mongoose.Types.ObjectID], required: true, ref: "Address" },
},
{
timestamps: true,
}
);
NOTICE:
In the first code, I surrounded the whole address object with square brackets.
In the second code, I only surrounded the type property of the address with square brackets.
What I want to know is how that will impact the app's behavior.
Is there any difference?
Thanks.
They both declare an array-of-references, but there are some subtle differences.
Let's take this simple schema:
const userSchema = mongoose.Schema({
address: { type: [ String ], required: true, default: undefined }
});
const User = mongoose.model('User', userSchema);
This will apply the options (required and default) to the address array-of-strings as a whole:
// This will fail validation:
// ValidatorError: Path `address` is required
const doc = new User({});
// This will pass validation:
const doc = new User({ address : [] });
Now change the position of the brackets in the schema:
const userSchema = mongoose.Schema({
address: [{ type: String, required: true, default: undefined }]
});
This will apply the options to the elements of the address array:
// This will pass validation, `address` itself isn't required:
const user = new User({});
// This will also pass validation, for the same reason:
const user = new User({ address : [] });
// This will fail validation, because elements of the array are required to have a proper value
// ValidatorError: Path `address.0` is required
const user = new User({ address : [ '' ] });
EDIT: if you want to enforce that the address field is always defined and has at least one element, you have to use a custom validator. For your schema, it would look like this:
address: {
type: [ mongoose.Schema.Types.ObjectID ],
ref: 'Address',
required: true,
default: undefined,
validate: a => Array.isArray(a) && a.length > 0
}

Mongoose find.where in a schema with an attribute of type ObjectId

I have this schemas:
UserLike
const UserLikeSchema = Schema({
user: {
type: Schema.Types.ObjectId,
ref: "User",
required: [true, "User is required"],
},
game: {
type: Schema.Types.ObjectId,
ref: "Game",
required: [true, "Game is required"],
}
});
Game
const GameSchema = Schema({
title: {
type: String,
required: [true, "Title is required"],
},
status: {
type: Boolean,
default: true,
},
});
I need to find all UserLikes where populated Game.status are true
I'm trying with a code like this
const games = await UserLike.find()
.populate("game")
.where("game.status")
.equals(true);
But I can't find a solution :(
You should try using the match option as directed by mongoose docs.
https://mongoosejs.com/docs/populate.html#query-conditions
The query might look something like this:
UserLike.
find().
populate({
path: 'game',
match: { status: true },
}).
exec();

Mongoose Automatically Decreases Field with Type of Number

i have used mongoose for my project currently, and this is my Schema:
const mongoose = require('mongoose');
const classSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
consultant: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Consultant',
required: true,
},
faculty: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Faculty',
required: true,
},
startYear: {
type: String,
required: true,
},
currentSchoolYear: {
type: String,
required: true,
},
currentSemester: {
type: String,
required: true,
},
classname: {
type: String,
required: true,
unique: true,
},
classSize: {
type: Number,
required: true,
},
warnedLength: {
type: Number,
required: true,
},
});
const Class = mongoose.model('Class', classSchema);
module.exports = Class;
as you can see, i have 2 properties are classSize and warnedLength are Number. Now i want to make a function that when i onClick a button from the client, the value of classSize and warnedLength will automatically decrease by 1. is there anyway to do that, thank you so much for help me out, it means a lot to me, have a good day

Querying sub document of sub document in mongoose

I wanted to save the data in "messageSchema" which is sub document of chatSchema by checking the "receiver" of chatSchema and "username" of userSchema.
like pseudoCode:-
if(userSchema.username == "Rahul" && userSchema.chatSchema.receiver){
then save the data in chatSchema.message;
}
Here is my Schema:-
var messageSchema = mongoose.Schema({
messageId: {type: String, unique: true, required: true},
created: {type: Date, default: Date.now},
messageContent: String
});
var chatSchema = mongoose.Schema({
message: [messageSchema],
receiver: {type: String, required: true}
});
var userSchema = mongoose.Schema({
username: { type: String, unique: true, required: true },
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
token: { type: String, required: false },
conversations: [chatSchema]
});
please suggest what should be code to save the message data.
tried below one that didn't work.
User.findOneAndUpdate({username: "rahul", "conversations.receiver": data.receiver },{$push: {"conversations.message": message}});
I think you need to use $elemMatch instead of the dot notation for matching properties within an array. Try this:
User.findOneAndUpdate(
{
username: "rahul",
conversations: {
$elemMatch: { receiver: data.receiver }
}
},
// or whatever your update is
{$push: {"conversations.message": message}
})

Returning specific fields with mongoose

I'm trying to accomplish something really easy but still manage to fail.
What I am trying to do is when I get a get request on my server I want to return all documents BUT just the specific fields populated.
My schema goes as follows
var clientSchema = new Schema({
name:{
type: String,
required: true
},
phone:{
type: String,
required: true
},
email:{
type: String,
required: true
},
address: {
type: String,
required: false
}
});
var orderDetailsSchema = new Schema({
//isn't added to frontend
confirmed:{
type: Boolean,
required: true,
default: false
},
service:{
type: String,
required: true
},
delivery:{
type: String,
required: false
},
payment:{
type: String,
required: false
},
status:{
type: String,
required: true,
default: "new order"
},
});
var orderSchema = new Schema({
reference:{
type: String,
required: true
},
orderdetails: orderDetailsSchema,
client: clientSchema,
wheelspec: [wheelSchema],
invoice:{
type: Schema.Types.ObjectId,
ref: 'Invoice'
}
});
What I want is to return only client.phone and client.email plus orderdetails.status but still retain reference field if possible
I have tried using lean() and populate() but had no luck with them. Is there anything utterly simple I am missing? Or what I am trying to achieve is not that easy?
Thanks!
You can specify the fields to return like this:
Order.findOne({'_id' : id})
.select('client.phone client.email orderdetails.status reference')
.exec(function(err, order) {
//
});
Alternative syntax
Order.findOne({'_id' : id})
.select('client.phone client.email orderdetails.status reference')
.exec(function(err, order) {
//
});
I've made a number of assumptions here, but you should be able to see the idea.
Simply do like this :-
Order is model name which is registered in mongoose.
Order.findById(id) // set id you have to get
. populate('client')
.select('client.phone client.email orderdetails.status reference')
.exec(function(err, order) {
//
});
You can use projection.
await Order.findById(diaryId, {phone: 1, email: 1, status: 1})
If phone:1 is set to 1, it is included, if phone:0, then it's excluded.

Categories