sails update the doc, nothing happen, not err message - sails.js

eventController:
newHelper: function(req, res) {
const eventID = req.body.eventID;
let newHelper = req.body.newHelper;
newHelper.eventAssoc = eventID;
Wapphelprecords.create(newHelper).exec(function(err, newhelper) {
if (err) {
return res.serverError(err); }
sails.log('add new helper:', newhelper);
return res.json(newhelper);
});
}
when I do this action, the database nothing happen, and no err message, this is model under blow:
WappeventController model:
module.exports = {
attributes: {
eventID: {
type: 'integer',
// autoIncrement: true,
unique: true,
// defaultsTo: 0
},
openid: {
type: 'string',
},
author: {
model: 'wappuserinfo'
},
content: {
type: 'string'
},
allowShare: {
type: 'boolean'
},
imageList: {
type: 'array'
},
money: {
type: 'float',
},
helpers: {
collection: 'wapphelprecords',
via: 'eventAssoc',
},
bestHelper: {
collection: 'wapphelprecords',
via: 'eventAssoc',
}
},
Wapphelprecords Model:
module.exports = {
attributes: {
eventAssoc: {
model: 'wappevents',
},
content: {
type: 'string'
},
contact: {
type: 'string'
},
userInfo: {
model: 'wappuserinfo'
},
bestHelper: {
type: 'boolean'
},
moneyEarn: {
type: 'float'
}
}
};
when I do newHelper action, the database nothing happened, and nothing error notice, I just do not understand. need help, thx.

spend whole day to fix it, and finally:
module.exports = {
attributes: {
eventID: {
type: 'integer',
// autoIncrement: true,
primaryKey: true, //<---- set this primarkey to true
unique: true,
// defaultsTo: 0
},
openid: {
type: 'string',
},
author: {
model: 'wappuserinfo'
},
content: {
type: 'string'
},
allowShare: {
type: 'boolean'
},
imageList: {
type: 'array'
},
money: {
type: 'float',
},
helpers: {
collection: 'wapphelprecords',
via: 'eventAssoc',
},
bestHelper: {
collection: 'wapphelprecords',
via: 'eventAssoc',
}
},

Related

How to fetch data from multiple collections in MongoDB?

How to fetch data from multiple collections in MongoDB by using a common field and sending data (in those fetched collections) using one response?
Employee Scheema:
const mongoose = require("mongoose");
const employeeSchema = new mongoose.Schema(
{
profilePic: {
type: String,
},
employeeID: {
type: String,
required: true,
},
employeeFirstName: {
type: String,
required: true,
},
employeeLastName: {
type: String,
required: true,
},
birthday: {
type: String,
},
streetNo: {
type: String,
},
city: {
type: String,
},
phoneNumber: {
type: String,
},
jobRole: {
type: String,
required: true,
},
NIC: {
type: String,
required: true,
unique: true,
},
companyEmail: {
type: String,
required: true,
unique: true,
},
status: {
type: String,
required: true,
},
resignDate: {
type: String,
},
jobType: {
type: String,
required: true,
},
candidateID: {
type: String,
required: true,
},
teamID: {
type: String,
},
lastSeen: {
type: String,
},
token: {
type: String,
},
},
{ timestamps: true }
);
module.exports = mongoose.model("employee", employeeSchema);
Acadamic Qualification Scheema:
const mongoose = require("mongoose");
const academicQualificaationSchema = new mongoose.Schema(
{
employeeID: {
type: String,
required: true,
},
ordinaryLevelResult: {
type: Array,
required: true,
},
advancedLevelResults: {
type: Array,
required: true,
},
achievements: {
type: Array,
required: true,
},
},
{ timestamps: true }
);
module.exports = mongoose.model(
"academicQualification",
academicQualificaationSchema
);
Professional Qualification Scheema:
const mongoose = require("mongoose");
const proffesionalQualificaationSchema = new mongoose.Schema(
{
employeeID: {
type: String,
required: true,
},
degree: {
type: Array,
required: true,
},
language: {
type: Array,
required: true,
},
course: {
type: Array,
required: true,
},
},
{ timestamps: true }
);
module.exports = mongoose.model(
"proffesionalQualification",
proffesionalQualificaationSchema
);
Controller:
exports.viewEmployees = async (req, res) => {
try {
let accQuali, profQuali;
const employees = await employeeSchema.find();
accQuali = await academicQualificaationSchema.find();
profQuali = await ProffesionalQualificationSchema.find();
if (employees || accQuali || profQuali) {
return res.status(200).json({ data: { employees, profQuali, accQuali } });
} else {
return res.status(404).json({ message: message });
}
} catch (err) {
return res.status(404).json({ err: err.message });
}
};
This controller is working properly and sends all data in 3 collections with the use of one response. But, I am comfortable if I will be able to Fetch data separately for each employee.
If you want to get the data from the three collections for specific employee or employees, you can use an aggregation pipeline with a $lookup stage, as suggested by #1sina1. For example:
db.employee.aggregate([
{
$match: {"employeeID": "IDA"}
},
{
$lookup: {
from: "academicQualification",
localField: "employeeID",
foreignField: "employeeID",
as: "academicQualification"
}
},
{
$lookup: {
from: "proffesionalQualification",
localField: "employeeID",
foreignField: "employeeID",
as: "proffesionalQualification"
}
}
])
As you can see on the playground

How to set common where param to all models in query, in sequelize

I'm trying to realize the query, where I can find all records, which at least one of the attributes includes the text, user send with request, for that I use where, but it can search, as I understand, in only own model, but i need it to search it in parent model and in associated filds together, not apart.
There is my models:
const Picture = sequelize.define<IPictureInstance>('picture', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
img: { type: DataTypes.STRING, allowNull: false },
mainTitle: { type: DataTypes.STRING, allowNull: false },
description: { type: DataTypes.TEXT }
});
const PictureInfo = sequelize.define<IPictureInfoInstance>('pictureInfo', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
title: { type: DataTypes.STRING, allowNull: false },
description: { type: DataTypes.STRING, allowNull: false }
});
const PictureTag = sequelize.define<IPictureTagInstance>('pictureTag', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
text: { type: DataTypes.TEXT, allowNull: false }
});
const PicturesTags = sequelize.define<IPicturesTagsInstance>('picturesTags', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }
});
And their associations:
Picture.belongsToMany(PictureTag, { through: PicturesTags, as: "tags", onDelete: 'cascade' });
PictureTag.belongsToMany(Picture, { through: PicturesTags, as: "pictures", onDelete: 'cascade'
});
Picture.hasMany(PictureInfo, { onDelete: "cascade" });
PictureInfo.belongsTo(Picture);
That's what I tried to do:
static async getPictures(query: string | undefined) {
const pictures = await models.Picture.findAll({
where: {
[Op.or]: {
mainTitle: { [Op.iRegexp]: `${query}` },
description: { [Op.iRegexp]: `${query}` },
},
},
include: [
{
model: models.PictureInfo,
as: "pictureInfos",
where: {
[Op.or]: {
title: { [Op.iRegexp]: `${query}` },
description: { [Op.iRegexp]: `${query}` }
}
},
required: false
},
{
model: models.PictureTag,
as: "tags",
attributes: ["id", "text"],
where: { text: { [Op.iRegexp]: `${query}` } },
through: {
attributes: [],
},
required: false
}
],
});
return pictures;
}
But in this case, when it can't find records in first where param it returns an empty array, I understand it, but it isn't a behavior I need.
I need to check every attribute together.
So, if user send query=cat, it will check mainTitle and description, if there is nothing, it will check associated pictureInfos fields and after, if there is nothing, check pictureTags associated fields, that's what I need, will be grateful for the help.
My solution:
static async getPictures(query: string | undefined) {
const whereStatement = {
[Op.or]: {
mainTitle: { [Op.iRegexp]: `${query}` },
description: { [Op.iRegexp]: `${query}` },
"$tags.text$": { [Op.iRegexp]: `${query}` },
"$pictureInfos.title$": { [Op.iRegexp]: `${query}` },
"$pictureInfos.description$": { [Op.iRegexp]: `${query}` },
}
};
const pictures = await models.Picture.findAll({
where: whereStatement,
include: [
{
model: models.PictureInfo,
as: "pictureInfos",
},
{
model: models.PictureTag,
as: "tags",
}
],
});
return pictures;
}
But I'm still confused with those $ symbols, what they are for, I couldn't find the answer in documentation?
Link to the Sequelize documentation, to confirm my answer

How do you update a nested array with Mongoose?

This is what I have so far. This is my AnswerSchema with a comments array nested within that I am trying to update.
const AnswerSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'user',
},
question: {
type: Schema.Types.ObjectId,
ref: 'question',
},
text: {
type: String,
required: true,
},
name: {
type: String,
},
avatar: {
type: String,
},
views: {
type: Number,
},
date: {
type: Date,
default: Date.now,
},
answerLikes: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'user',
},
},
],
comments: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'user',
},
text: {
type: String,
required: true,
},
name: {
type: String,
},
avatar: {
type: String,
},
commentLikes: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'user',
},
},
],
date: {
type: Date,
default: Date.now,
},
},
],
})
and here is my update route that I am trying to use to update the comments array text field
try {
const updatedAnswer = await Answer.findOneAndUpdate(
{ _id: req.params.answer_id },
{
$set: { 'comments.$[comment].text': formattedAnswer },
},
{
arrayFilters: [{'comment._id': req.params.comment_id }],
},
{ new: true }
)
res.json(updatedAnswer)
I keep getting the error 'Callback must be a function, got [object Object]' and cant figure out a fix.
Any ideas?
Thanks!
The problem in your code is that you are passing 4 parameters to the findOneAndUpdate function.
The 4th argument is a callback which accepts a function:
(err /* an error if occurred */, doc /* the updated document */) => {}
In order to solve that you need to combine your last 2 arguments into one object like:
{
arrayFilters: [{'comment._id': req.params.comment_id }],
new: true
}
Final query:
const updatedAnswer = await Answer.findOneAndUpdate(
{ _id: req.params.answer_id },
{
$set: { 'comments.$[comment].text': formattedAnswer },
},
{
arrayFilters: [{'comment._id': req.params.comment_id }],
new: true
}
)
The 4th argument in findOneAndUpdate function takes in a callback function that was where your error was.
Try this
try{
const updatedAnswer = await Answer.findOneAndUpdate(
{ _id: req.params.answer_id },
{
$set: { 'comments.$[comment].text': formattedAnswer },
},
{
arrayFilters: [{'comment._id': req.params.comment_id }],
new: true
}
);
res.json(updatedAnswer);
}catch(err){
//console.log(err)
}

Sequelize Model associations - foreign key missing

I have 2 models that I am associating like this. Customer is associated to application by 1:M relationship.
customer:
'use strict';
module.exports = (sequelize, DataTypes) => {
let customer = sequelize.define('customer', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING
},
account_id: {
type: DataTypes.STRING
},
code: {
type: DataTypes.STRING
},
createdAt: {
type: DataTypes.DATE,
defaultValue: sequelize.literal('NOW()')
},
updatedAt: {
type: DataTypes.DATE,
defaultValue: sequelize.literal('NOW()')
}
},
{
underscored: true,
freezeTableName: true,
tableName: 'customer'
});
customer.associate = function(models) {
// associations can be defined here
customer.hasMany(models.application, { foreignKey:
'customer_id' });
};
sequelize.sync()
.then(() => customer.create(
{ name: "customer1", account_id: "cust-1-acct-1", code: "ACME Inc." }
)).then(function(customer) {
console.log('customers created');
}).then(() => customer.create(
{ name: "customer2", account_id: "cust-2-acct-2", code: "test Cust" }
)).then(function(customer) {
console.log('customers created');
})
.catch(function(err) {
console.log(err);
});
return customer;
}
application:
'use strict';
module.exports = (sequelize, DataTypes) => {
let application = sequelize.define('application', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING,
sortable: true
},
creation_date: {
type: DataTypes.NUMERIC,
sortable: true
},
customer_id: {
type: DataTypes.INTEGER
},
createdAt: {
type: DataTypes.DATE,
defaultValue: sequelize.literal('NOW()')
},
updatedAt: {
type: DataTypes.DATE,
defaultValue: sequelize.literal('NOW()')
}
},
{
underscored: true,
freezeTableName: true,
tableName: 'application'
});
application.associate = function(models) {
// associations can be defined here
application.belongsTo(models.customerView, { through: 'customer_id' });
};
sequelize.sync()
.then(() => application.create(
{ customer_id: "1", name: "application 1", creation_date: "1556724178700" }
)).then(() => application.create(
{ customer_id: "1", name: "application 2", creation_date: "1556724178700" }
)).then(() => application.create(
{ customer_id: "2", name: "application 3", creation_date: "1556724178700" }
))
.then(function(application) {
console.log('applications created');
})
.catch(function(err) {
console.log(err);
});
return application;
}
These 2 tables are getting created as expected, but without the foreign key constraint that I am expecting. The foreign key should be on the application table, on customer_id.
What am I doing wrong?

Eager Loading : How to disable specific fields of included table

I am trying to do Eager Loading in Sequelize with PostgreSQL where I need to find the Users which have a given specific Mail id or basically, i am performing find operation on Mail model while using include to include User model
UserModel :
module.exports = function (sequelize, Sequelize) {
var User = sequelize.define('User', {
userId: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
firstname: {
type: Sequelize.STRING,
require: true
},
lastname: {
type: Sequelize.STRING,
require: true
},
age: {
type: Sequelize.INTEGER,
require: true
},
phone: {
type: Sequelize.STRING,
require: true
},
location: {
type: Sequelize.STRING,
require: true
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
}
});
return User;
};
MailModel :
module.exports = function (sequelize, Sequelize) {
var User = require('./User.js')(sequelize, Sequelize)
var Mail = sequelize.define('Mail', {
name: {
type: Sequelize.STRING,
require: true
}
});
Mail.belongsTo(User);
return Mail;
};
MailController :
var db = require('../services/db.js');
module.exports = {
create: function (req, res, next) {
var Mailm = db.MailModel;
var name = req.body;
try {
db.sequelize.sync().then(function () {
Mailm.create(name).then(function (found) {
return res.json({
success: true,
message: found.get({
plain: true
})
});
})
});
} catch (ex) {
res.json({
success: false,
exception: ex
});
return;
}
},
query: function (req, res, next) {
var Mailm = db.MailModel;
var Userm = db.UserModel;
var name = req.body;
var option = {};
option.where = name;
option.include = [{
model: Userm
}];
try {
Mailm.findAll(option).then(function (found) {
console.log(found);
return res.json({
success: true,
message: found
});
});
} catch (ex) {
res.json({
success: false,
exception: ex
});
return;
}
}
};
It is returning me the records of both User and Mail table in exactly the right way .
Output :
{
"success": true,
"message":[
{
"id": 2,
"name": "Mailb2",
"createdAt": "2015-07-30T07:32:51.807Z",
"updatedAt": "2015-07-30T07:32:51.807Z",
"UserUserId": 2,
"User":{
"userId": 2,
"firstname": "Prerna",
"lastname": "Jain",
"age": 20,
"phone": "9812123456",
"location": "Sirsa",
"createdAt": "2015-07-30T07:30:48.000Z",
"updatedAt": "2015-07-30T07:30:48.000Z"
}
}
]
}
But I want to disable createdAt and updatedAt fields of User table so that it does not give me these two fields in the output for User.
I have tried a lot as of how to do this but still in vain.Can anyone please help me out.
I bet this is coming late, add attribute/properties to your models called timestamps, it accepts a boolean as a value. For example:
module.exports = function (sequelize, Sequelize) {
var User = require('./User.js')(sequelize, Sequelize)
var Mail = sequelize.define('Mail', {
name: {
type: Sequelize.STRING,
require: true
}
},
{
// This does the magic
timestamps: false,
});
Mail.belongsTo(User);
return Mail;
};
Also, add it to the User model:
var User = sequelize.define('User', {
userId: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
firstname: {
type: Sequelize.STRING,
require: true
},
lastname: {
type: Sequelize.STRING,
require: true
},
age: {
type: Sequelize.INTEGER,
require: true
},
phone: {
type: Sequelize.STRING,
require: true
},
location: {
type: Sequelize.STRING,
require: true
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
}
},
{
timestamps: false
});
return User;
};
You can use
Model.findAll({
attributes: { exclude: ['baz'] }
});
more examples with attributes - http://docs.sequelizejs.com/en/latest/docs/querying/#attributes