How to access inner object in keystoneJS - node.js

Say I have a model like
University.add({
university_id: { type: Types.Number, required: true, initial: true, index: true, unique: true },
name: { type: Types.Text, required: true, index: true },
address: { type: Types.Text, initial: true, required: false, index: false }
});
University.schema.add({
"inner_object": {
"name": String,
"phone": String,
"comment": String
}
});
I tried updating the object using getUpdateHandler()
University.model.findOne().where('university_id', universityData.university_id).exec(function (err, university) {
university.getUpdateHandler(req, res).process(req.body, {
fields: "name, address, 'inner_object.name', 'inner_object.phone', 'inner_object.comment'"
}, function(err) {
if(err) {
console.log(err);
res.json({ status: false, data: null, message: 'Error while creating university'});
} else {
res.json({ message: 'University updated successfully', status: true, data: university});
}
});
});
Iam getting an error UpdateHandler.process called with invalid field path: inner_object.name
Please update if anyone went through the same scenario

You're adding the inner_object outside of keystone, directly through mongoose, which means keystone won't have knowledge about its existence. Just add it to the first configuration object:
University.add({
university_id: { type: Types.Number, required: true, initial: true, index: true, unique: true },
name: { type: Types.Text, required: true, index: true },
address: { type: Types.Text, initial: true, required: false, index: false },
inner_object: {
name: {type:String},
phone: {type:String},
comment: {type:String}
}
});

Related

mongoose ^6.0.12 findandupdate on models with required fields

I have updated my mongoose to version 6.0.12 but since that all usually workings findoneandupdate operations on models that have required fields and other validations rules stopped working
try {
await UserModel.findByIdAndUpdate(
req.body.userId,
{ $set : {picture: "./uploads/profile/" + fileName}},
{ new: true, upsert: true, setDefaultsOnInsert: true},
(err, docs) => {
if (!err) return res.send(docs);
else return res.status(500).send({ message: err });
}
);
} catch (err) {
return res.status(500).send({ message: err });
}
onst userSchema = new mongoose.Schema(
{
pseudo: {
type: String,
required: true,
minLength: 3,
maxLength: 55,
unique: true,
trim: true
},
email: {
type: String,
required: true,
validate: [isEmail],
lowercase: true,
unique: true,
trim: true,
},
password: {
type: String,
required: true,
max: 1024,
minlength: 6
},
picture: {
type: String,
default: "./uploads/profile/random-user.png"
},
bio :{
type: String,
max: 1024,
},
followers: {
type: [String]
},
following: {
type: [String]
},
likes: {
type: [String]
}
},
{
timestamps: true,
}
);
I got this errors just after the updrade
"originalStack": "Error\n at model.Query._wrappedThunk [as _findOneAndUpdate] (C:\Users\amen\NODE\mern-project\node_modules\mongoose\lib\helpers\query\wrapThunk.js:25:28)\n
at
C:\Users\amen\NODE\mern-project\node_modules\kareem\index.js:279:20\n
at _next
(C:\Users\amen\NODE\mern-project\node_modules\kareem\index.js:103:16)\n
at
C:\Users\amen\NODE\mern-project\node_modules\kareem\index.js:508:38\n
at processTicksAndRejections
(internal/process/task_queues.js:77:11)"
thank you in advance
Regards

How to keep id on mongoose findByIdAndUpdate

I am trying to update a 'Board' model in mongoose using findByIdAndUpdate and the model has an array of 'items' (which are objects) on the model. I probably do not understand mongoose well enough but for some reason each item in the array gets an id generated, along with the Board. This is not a problem, it's quite handy actually, however, after doing a findByIdAndUpdate the id on each item has changed. This was quite surprising to me, I really thought they would stay the same. Could this be caused by updating all items in the array? Maybe mongoose is just throwing out the entire array and creating a new one when updating (maybe someone knows?). Anyways, my question is: Is there a way to update the model without changing these id's. I would really like them to stay consistent. The code I am using for update is
exports.updateBoard = asyncHandler(async (req, res, next) => {
let board = await Board.findById(req.params.id);
if (!board) {
return next(new CustomError(`Board not found with id of ${req.params.id}`, 404));
}
// Authorize user
if (board.user.toString() !== req.user.id) {
return next(new CustomError(`User ${req.user.id} is not authorized to update board ${board._id}`, 401));
}
req.body.lastUpdated = Date.now();
board = await Board.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true })
.select('-__v')
.populate({
path: 'user',
select: 'name avatar',
});
// 200 - success
res.status(200).json({ success: true, data: board });
});
and BoardSchema:
const BoardSchema = new Schema(
{
user: {
type: Schema.Types.ObjectId,
ref: 'User',
required: [true, 'Board must have a user'],
},
name: {
type: String,
required: true,
trim: true,
},
description: {
type: String,
required: false,
trim: true,
},
items: [
{
title: {
type: String,
required: true,
trim: true,
},
description: {
type: String,
required: false,
trim: true,
},
dateCreated: {
type: Date,
default: Date.now,
},
lastUpdated: {
type: Date,
default: Date.now,
},
},
],
columns: [
{
name: {
type: String,
required: true,
},
index: {
type: Number,
required: true,
},
show: {
type: Boolean,
required: true,
},
},
],
dateCreated: {
type: Date,
default: Date.now,
},
lastUpdated: {
type: Date,
default: Date.now,
},
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true },
},
);

Add data in an array of object with mongoDB

I need your help, I try to add(if it not exists) or update if exists datas in an array of Object in MongoDB.
Here is my Model
import { Schema, model } from "mongoose";
const userSchema = new Schema({
firstName: {
type: String,
required: true,
unique: false,
trim: true
},
pseudo: {
type: String,
required: true,
unique: true,
trim: true,
minlength: 3
},
email: {
type: String,
required: false,
trim: true
},
password: {
type: String,
required: true
},
// password2: {
// type: String,
// required: true
// },
tags: {
type: Array,
required: false
},
address: {
type: String,
required: true,
unique: false,
trim: true
},
coord: {
type: Object,
required: false,
unique: false,
trim: true
},
poll: [
{
tag: String,
dates: Array
}
]
},
{
timestamps: true,
});
const User = model('User', userSchema);
export default User;
My route
router.route('/calendar/:email').post((req, res) => {
User.findOne({ email: req.body.email }).then( (user) =>{
console.log("user 1", user)
User.bulkWrite([
{
insertOne: {
"poll": {
"tag": req.body.selectedTag,
"dates": req.body.datesArray
}
}
},
{
updateOne: {
"filter": {
"tag" : req.body.selectedTag
},
"update": {
$set: {
"dates": req.body.datesArray
}
},
}
}
])
})
});
and the datas sended :
email: 'john#gmail.com',
selectedTag: 'work',
dateArray: [ '2020-07-16T22:00:00.000Z' ]
I try many things like by findOneaAndUpdate, but I don't know how to add in the array "poll", objects with tag and the dates associated.
If somebody could help me it would be very nice !
I shoul use add $addToSet or $push, depending if the element is unique or not.
Something like this:
"update": {
"$addToSet": {
"poll": { /*...*/ }
}
}
For reference:
http://docs.mongodb.org/manual/reference/operator/update/addToSet/
http://docs.mongodb.org/manual/reference/operator/update/push/

Dynamic type select in keystonejs model

I would like to use a combobox at the adminUI with fields that come from a webservice. I was thinking on get the data with a pre 'find' hook and then override the options atribute at the 'audience' property in the Schema.
Schema:
Compliance.add({
title: { type: Types.Text, required: true, initial: true, index: true },
url: { type: Types.Url, required: true, initial: true },
position: { type: Types.Number, initial: true },
audience: { type: Types.Select, options: [], many: true, initial: true},
});
Hook:
Compliance.schema.pre('find', async function(next) {
let audiences = await audienceService.getAudiences();
next();
})
But I didn't find the way to bind the data. Any ideas how this can be done?
Thanks
You can try making a function from the options:
function getAudiences() {
return ['a', 'b', 'c'];
}
Compliance.add({
title: { type: Types.Text, required: true, initial: true, index: true },
url: { type: Types.Url, required: true, initial: true },
position: { type: Types.Number, initial: true },
audience: { type: Types.Select, many: true, initial: true, options: getAudiences() }
});
Result as below:

Waterline trying to access ID field

Currently Im using this model (with sails.js)
module.exports = {
tableName: 'player_deaths',
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
player_id: {
required: true,
type: 'integer'
},
time: {
required: true,
type: 'integer'
},
level: {
required: true,
type: 'integer'
},
killed_by: {
required: true,
type: 'string'
},
is_player: {
required: true,
type: 'integer'
},
mostdamage_by: {
required: true,
type: 'string'
},
mostdamage_is_player: {
required: true,
type: 'integer'
},
unjustified: {
required: true,
type: 'integer'
},
mostdamage_unjustified: {
required: true,
type: 'integer'
}
},
autoPk: false,
}
And im calling it like this
PlayersDeaths.find().sort('time desc').exec(function(err, data) {
if(err || data.length === 0) {
console.log(err,data)
req.flash('errors', 'No deaths found');
return res.redirect('/');
}
return res.view('community/deaths', { deaths: data});
});
Thing is im getting this error
Unknown column 'playersdeath.id' in field list
Checking my model I dont even see the ID attribute listed... so why is it trying to access it?!
(the table does not have a pk)
Looks like a primary key is required. If you use autoPk:false then you need to define a PK your self see https://github.com/balderdashy/waterline-docs/blob/master/models.md#autopk
However, you still maybe able to avoid this by using model.native() or model.query() (depending on your adapter)
http://sailsjs.org/#!/documentation/reference/waterline/models/native.html
http://sailsjs.org/#!/documentation/reference/waterline/models/query.html
If you have a database Schema defined, maybe you need set you model like this
module.exports = {
migrate: 'safe',
autoPK : false,
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
// ------
}

Resources