I am using a sailsjs framework for an app. I am building, and I am trying to extract the id value from a model I have:
const memoryCreatorId = _(Memory.creator).map('id').value();
console.log(memoryCreatorId);
const message = {
app_id: '***********************',
contents: {"en": "Yeah Buddy, Rolling Like a Big Shot!"},
filters: [{"field": "tag", "key": "userId", "relation": "=", "value": memoryCreatorId}],
ios_badgeType: 'Increase',
ios_badgeCount: 1
};
return PushNotificationService.sendNotification(message);
I'm basically trying to get what would be the Memory.creator.User.id value. So basically the userid of the person who creates a memory. I'm trying to get it from the "Memory" model "creator" attribute, which maps to the "User" model, and from the "User" model, extract the "id" attribute. Thanks for your help in advance!
Memory model below:
Memory.js
const _ = require('lodash');
module.exports = {
attributes: {
creator: {
model: 'User'
},
title: {
type: 'string'
},
description: {
type: 'text'
},
contentUrl: {
type: 'string',
url: true
},
cropRect: {
type: 'string'
},
likers: {
collection: 'User',
via: 'memoryLikes'
},
comments: {
collection: 'Comment',
via: 'memory'
},
update: {
model: 'Update',
},
cause: {
model: 'Cause',
}
}
};
User model is a follows:
User.js
'use strict';
const uuid = require('node-uuid');
const CipherService = require('../services/CipherService');
const BraintreeService = require('../services/BraintreeService');
module.exports = {
attributes: {
id: {
type: 'string',
primaryKey: true,
defaultsTo: () => uuid.v4(),
unique: true,
index: true,
uuidv4: true
},
firstName: {
type: 'string',
defaultsTo: ''
},
lastName: {
type: 'string',
defaultsTo: ''
},
email: {
type: 'string',
email: true,
required: true,
unique: true
},
password: {
type: 'string'
},
passwordResetToken: {
type: 'string'
},
passwordResetTokenExpires: {
type: 'string'
},
type: {
type: 'string',
enum: ['admin', 'member']
},
city: {
type: 'string'
},
state: {
type: 'string'
},
address: {
type: 'string'
},
institution: {
model: 'Institution'
},
major: {
type: 'string'
},
contentUrl: {
type: 'string',
url: true,
defaultsTo: AwsService.getAssetImageUrl('user-default.png')
},
cropRect: {
type: 'string'
},
graduationYear: {
type: 'integer'
},
donations: {
collection: 'Donation',
via: 'donor'
},
memories: {
collection: 'Memory',
via: 'creator'
},
causes: {
collection: 'Cause',
via: 'followers',
dominant: true
},
adminCauses: {
collection: 'Cause',
via: 'admins'
},
isLeader: {
type: 'boolean',
defaultsTo: false
},
isCurrentStudent: {
type: 'boolean',
defaultsTo: false
},
isAdmin: {
type: 'boolean',
defaultsTo: false
},
adminTitle: {
type: 'string'
},
paymentProfile: {
model: 'PaymentProfile'
},
jsonWebTokens: {
collection: 'Jwt',
via: 'owner'
},
memoryLikes: {
collection: 'Memory',
via: 'likers'
},
updateLikes: {
collection: 'Update',
via: 'likers'
},
toJSON: function() {
return User.clean(this);
}
},
beforeUpdate: (values, next) => {
CipherService.hashPassword(values).then(() => next()).catch(next);
},
beforeCreate: (values, next) => {
CipherService.hashPassword(values).then(() => next()).catch(next);
},
clean: (user) => {
//let obj = user.toObject();
delete user.password;
delete user.jsonWebTokens;
delete user.passwordResetToken;
delete user.passwordResetTokenExpires;
return user;
}
};
Related
So I created this controller to get me the sum of all the orders totalPrice made by months
const getMonthlyOrderTotal = async (req, res) => {
try {
const year = req.params.year;
const aggregatePipeline = [
{
$match: {
createdAt: {
$gte: new Date(`${year}-01-01T00:00:00.000`),
$lt: new Date(`${year}-12-31T23:59:59.999`)
}
}
},
{
$group: {
_id: {
$month: "$createdAt"
},
total: {
$sum: "$totalPrice"
}
}
},
{
$sort: {
_id: 1
}
}
];
const orderTotals = await Order.aggregate(aggregatePipeline);
res.json(orderTotals);
} catch (err) {
res.status(500).json({ message: err.message });
}
};
this is the orderModel I am using
import mongoose from "mongoose";
const orderSchema = mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "User",
},
client: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "Client",
},
orderItems: [
{
name: { type: String, required: true },
qty: { type: Number, required: true },
image: { type: String },
price: { type: Number, required: true },
product: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "Product",
},
},
],
totalPrice: {
type: Number,
required: true,
default: 0.0,
},
taxPrice: {
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);
export default Order;
and when I try to test this API in postman "http://localhost:5001/orders/orderstotal/2022" I always get an empty array even though there is stored data in mongoDB orders Collection
i am working on a project based on GraphQL API with nodejs And mongoose
so i have this Model Below :
const mongoose = require('mongoose')
const BreakingNewsSchema = new mongoose.Schema({
MainInfo:{
content:{type:String,required:true},
ParentCategory:{
type: mongoose.Schema.Types.ObjectId,
ref: 'ArticleCategory',
required: true
},
category:{
type: mongoose.Schema.Types.ObjectId,
ref: 'ArticleCategory',
required: true
},
},
options:{
clickable:{type:Boolean,required:true},
link:{type:String,required:false},
isActive:{type:Boolean,required:true,default:true}
},
infos:{
createdAt: { type: String, required: true},
updateDate: {type: String, required: false},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
},
updatedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: false,
}}} ,{
timestamps: true})
module.exports = mongoose.model("BreakingNews", BreakingNewsSchema)
and i have this GraphQL Schema here :
const BreakingType = new GraphQLObjectType({
name: "BreakingNews",
fields: () => ({
id: {
type: GraphQLID
},
MainInfo: {
type: new GraphQLObjectType({
name: "BreakingMainInfo",
fields: () => ({
content: {
type: GraphQLString
},
ParentCategory: {
type: CategoryType,
resolve(parent, args) {
return Category.findById(parent.MainInfo.parentCategory)
}
},
category: {
type: CategoryType,
resolve(parent, args) {
return Category.findById(parent.MainInfo.category)
}
}
})
})
},
options: {
type: new GraphQLObjectType({
name: "BreakingOptions",
fields: () => ({
clickable: {
type: GraphQLBoolean
},
link: {
type: GraphQLString
},
isActive: {
type: GraphQLBoolean
}
})
})
},
})})
For the breakingNews Collection in Mongodb
and below i have the Category Collection ... so here is the Category Model :
const CategorySchema = new mongoose.Schema({
MainInfo:{
title: {
type: String,
required: true,
unique: true
},
slug: {
type: String,
required: false,
unique: true
},
},
seo:{
metaDescription: { type: String, required: false },
metaKeywords: [{
type: String,
required: false
}]
},
options:{
isParent:{type:Boolean,required:true},
isEnded:{type:Boolean,required:true},
parentCategory: {
type: mongoose.Schema.Types.ObjectId,
ref: "ArticleCategory",
required: false,
set: v => v === '' ? null : v
}
},
info:{
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
},
updatedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: false
},
articleCount:{type:Number,required:false},
oldId: { type: String, required: false }
}}, {
timestamps: true})
module.exports = mongoose.model("ArticleCategory", CategorySchema)
And finally i have the ArticleCategory Schema for GraphQL :
const CategoryType = new GraphQLObjectType({
name: "ArticleCategory",
fields: () => ({
id: {
type: GraphQLID
},
MainInfo: {
type: new GraphQLObjectType({
name: "ArticleCategoryMainInfo",
fields: () => ({
title: {
type: GraphQLString
},
slug: {
type: GraphQLString
}
})
})
},
seo: {
type: new GraphQLObjectType({
name: "ArticleCategorySeo",
fields: () => ({
metaDescription: {
type: GraphQLString
},
metaKeywords: {
type: new GraphQLList(GraphQLString)
}
})
})
},
options: {
type: new GraphQLObjectType({
name: "ArticleCategoryOptions",
fields: () => ({
isParent: {
type: GraphQLBoolean
},
isEnded: {
type: GraphQLBoolean
},
parentCategory: {
type: CategoryType,
resolve(parent, args) {
return Category.findById(parent.options.parentCategory)
}
}
})
})
}
})})
The problem is when i try to execute this query on graphQL:
query{
ActiveBreakingNews{
id
MainInfo{
content
ParentCategory {
id
}
category{
id
}
}
}
}
I get this error Cannot read properties of undefined (reading 'category') or Cannot read properties of undefined (reading 'category')
i find out its a problem find resolve function in the schema ... but i don't know what the wrong and what should i do to fix it ... please Help and thanks in advance
I have a fastify route method with the following schema.
fastify.post('/club', createClubSchema, createClub(fastify));
const createClubSchema = {
schema: {
tags: ['club'],
security: [
{
ApiKeyAuth: [],
},
],
body: {
type: 'object',
required: ['name', 'description'],
properties: {
name: { type: 'string', minLength: 3 },
description: { type: 'string', minLength: 3 },
logoUrl: { type: 'string', minLength: 3 },
},
},
response: {
200: {
type: 'object',
properties: {
status: { type: 'string' },
data: {
type: 'object',
properties: {
name: { type: 'string' },
description: { type: 'string' },
id: { type: 'number' },
color: { type: 'string' },
logoUrl: { type: 'string' },
createdAt: { type: 'string' },
updatedAt: { type: 'string' },
},
},
},
},
},
},
preHandler: [grantAccess('create', 'club')],
};
Now this route is in folder where there is autohooks.js is located that has a prehandler hook of it's own which checks whether the request has token in it for authentication purposes.
The problem is after the preHandler hook is called on both the area the createClub controller method is called, so a total of 2 times.
What is the issue? and how can i solve this?
EDIT
This is the autoHooks.js file
const authentication = require('../../middlewares/authentication');
module.exports = async function (fastify, opts, next) {
fastify.addHook('preHandler', authentication.authenticate(fastify));
};
I am using sequelize and SQLite3. When I use the model in my code then it is generating wrong query. Can any one help me to fix this issue
This is my model defiantion
module.exports = function(sequelize, DataTypes) {
let product = sequelize.define('product', {
id: {
type: DataTypes.INTEGER(10).UNSIGNED,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING(200),
},
code: {
type: DataTypes.STRING(100),
},
desc: {
type: "BLOB",
},
productCategoryId: {
type: DataTypes.INTEGER(10).UNSIGNED,
references: {
model: 'product_category',
key: 'id'
}
},
costPrice: {
type: DataTypes.FLOAT,
},
sellPrice: {
type: DataTypes.FLOAT,
},
markup: {
type: DataTypes.FLOAT,
},
markupType: {
type: DataTypes.ENUM('AMOUNT','PERCENTAGE'),
},
imgAttachment: {
type: DataTypes.INTEGER(1),
},
minOrderQuantity: {
type: DataTypes.INTEGER(10),
},
minStockQuantity: {
type: DataTypes.INTEGER(10),
},
isComposite: {
type: DataTypes.INTEGER(1),
},
isAllowedOutOfStockSale: {
type: DataTypes.INTEGER(1),
defaultValue: '0'
},
isActive: {
type: DataTypes.INTEGER(1),
defaultValue: '0'
},
isDeceptive: {
type: DataTypes.INTEGER(1),
defaultValue: '0'
},
createdAt: {
type: DataTypes.DATE,
},
createdBy: {
type: DataTypes.INTEGER(10).UNSIGNED,
references: {
model: 'user',
key: 'id'
}
},
deletedAt: {
type: DataTypes.DATE,
},
deletedBy: {
type: DataTypes.INTEGER(10).UNSIGNED,
references: {
model: 'user',
key: 'id'
}
},
updatedAt: {
type: DataTypes.DATE,
},
updatedBy: {
type: DataTypes.INTEGER(10).UNSIGNED,
references: {
model: 'user',
key: 'id'
}
}
}, {
tableName: 'product',
timestamps: false,
defaultScope: {
where: {
isActive: true,
deletedAt: null,
}
}
});
// Association
product.associate = function(models) {
models.product.belongsTo(models.user);
models.product.belongsTo(models.user);
models.product.belongsTo(models.user);
models.product.belongsTo(models.product_category);
models.product.hasMany(models.product_composition);
};
return product;
}
This is my model implementation
models.findAll({})
.then(data => {
console.log(data)
.catch(err => {
console.log(err)
});
I am getting SequelizeDatabaseError. After investigation I trace out the generated query
SELECT `id`, `name`, `code`, `desc`, `productCategoryId`, `costPrice`, `sellPrice`, `markup`, `markupType`, `imgAttachment`, `minOrderQuantity`, `minStockQuantity`, `isComposite`, `isAllowedOutOfStockSale`, `isActive`, `isDeceptive`, `createdAt`, `createdBy`, `deletedAt`, `deletedBy`, `updatedAt`, `updatedBy`, `userId` FROM `product` AS `product` WHERE `product`.`id` = 1 AND `product`.`isActive` = 1 AND `product`.`deletedAt` IS NULL;
Why it is adding userId in query. This query works fine when I remove userId field from this generated query
That is because of this line :
This line will add a userId attribute to product to hold the primary key value for Product
models.product.belongsTo(models.user);
But This will not add the field , reason is , naming convention is followed for foreign key name productCategoryId but not in above case ,
models.product.belongsTo(models.product_category);
for that you should define that explicitly and you should also add alias name for association coz you are using one table for 3 relations , like
models.product.belongsTo(models.user , { as : 'delete_by' ,foreignKey: 'deletedBy'} );
models.product.belongsTo(models.user , { as : 'created_by' ,foreignKey: 'createdBy'} );
models.product.belongsTo(models.user , { as : 'updated_by' , foreignKey: 'updatedBy'} );
For more detail : DO READ
I'm using Sails v0.11.2 and MongoDB 3.2 on Mac OS X El Capitan and I'm trying to implement Many-To-Many association using Through option which isn't supported yet.
However, googling I found this Waterline Github Issue and elennaro, a github user, gave me a couple of links with some examples:
First one
Second one
I have tried to adapt them to my own Sails app but I can't make it works. I got no errors on the console but the record or document on the intermediary table is not created only the Form document in it's table.
These are my models:
User.js
module.exports = {
schema: true,
tableName: 'users',
autoCreatedAt: false,
autoUpdatedAt: false,
attributes:
{
email : { type: 'email', required: true, unique: true },
encrypted_password : { type: 'string' },
reset_password_token: { type: 'string', defaultsTo: null},
permission_level : { type: 'integer', required: true, min: 1, max: 3, defaultsTo: 0 },
belongs_to : { type: 'string', required: true, defaultsTo: 0 },
signin_count : { type: 'integer', required: true, defaultsTo: 1 },
status_active : { type: 'boolean', required: true, defaultsTo: false },
last_signin_at : { type: 'datetime', defaultsTo: function (){ return new Date(); } },
last_signin_ip : { type: 'string', defaultsTo: '0.0.0.0' },
// Add a reference to Person
person_id:
{
model: 'person'
},
// Add a reference to Forms collection
forms:
{
collection: 'form',
via: 'user_id',
through: 'userhasform'
},
has:
{
collection: 'userhasform',
via: 'form_id'
}
}
};
Form.js
module.exports = {
schema: true,
tableName: 'forms',
attributes:
{
name : { type: 'string', required: true, unique: true },
creator : { type: 'string', unique: false },
sequence: { type: 'integer', autoIncrement: true },
// Add a reference to Questions collection
questions:
{
collection: 'question',
via: 'form_id'
},
// Add a reference to the owners Users
owners: {
collection: 'user',
via: 'form_id',
through: 'userhasform'
}
}
};
UserHasForm.js
module.exports = {
schema: true,
tableName: 'users_have_forms',
attributes:
{
to_edit : { type: 'boolean' },
to_delete : { type: 'boolean' },
user_id : { model: 'user' },
form_id : { model: 'form' }
}
};
The controller in which I create a form and it is supposed the intermediary document is been created at the join table is:
FormController.js
module.exports = {
create: function (req, res)
{
var ownerJson = {},
tmpFolio;
// Get the logged user to make the Folio and then create the form
SessionService.getUser(req, createForm);
// Callback function
function createForm (err, session)
{
// If there's no logged user or any error
if (err || !session)
{
console.log(err);
return res.json(err.status, {error: err});
}
console.log('User to create Folio: ', session.id);
ownerJson.owner_a = session.first_name;
ownerJson.owner_b = session.second_name;
ownerJson.owner_c = session.last_name;
// Construct the Folio creator part like AVC
tmpFolio = FolioService.generateFolio(ownerJson);
Form.create({
name: req.body.name,
creator: tmpFolio
})
.then(function (form){
if (err)
{
console.log(err);
return res.json(err.status, {error: err});
}
// Create the jointable record
var createdRecord = UserHasForm.create({
to_edit: true,
to_delete: true,
user_id: session.id,
form_id: form.id
})
.then(function (createdRecord){
if (err)
{
console.log(err);
return res.json(err.status, {error: err});
}
return createdRecord;
});
return [form, createdRecord];
})
.spread(function (form, createdRecord){
return res.json(200,
{
message: 'The form was created successfuly!',
data: form,
sharing: createdRecord
});
})
.fail(function (err){
if (err)
{
console.log(err);
res.json(err.status, {error: err});
}
});
}
},
};
When I run this code I got the next error:
[ReferenceError: UserHasForm is not defined]
Unhandled rejection TypeError: Cannot read property 'toString' of undefined
So I suppose it can't find the model so I add the next line to the model at the beginning:
var UserHasForm = require('../models/UserHasForm');
And now I get the next error:
[TypeError: UserHasForm.create is not a function]
All this is following the the first example on the list.
Any idea why I'm getting this error?
Any kind of help will be welcomed!
Well after trying to many examples finally I found the solution thanks to #elennaro for all his support. The whole conversation could be found in the link to the chat we both started under the main question's comments.
Also I can tell you that the examples in the links provided by him (which are in the question above) works fine, the problem was that the version I was using didn't support the features that those examples show.
Basically what I had to do is to install the most recent version for NodeJS, SailsJS and Waterline.
In my case I actually have the next ones:
Node v5.3.0
Sails v0.11.3
Waterline v0.10.30
After that I have to make some changes to my models and at the end they look like this:
User.js
module.exports = {
schema: true,
tableName: 'users',
autoCreatedAt: false,
autoUpdatedAt: false,
attributes:
{
// username : { type: 'string', unique: true, minLength: 5, maxLength: 15 },
email : { type: 'email', required: true, unique: true },
encrypted_password : { type: 'string' },
reset_password_token: { type: 'string', defaultsTo: null},
permission_level : { type: 'integer', required: true, min: 1, max: 3, defaultsTo: 0 },
belongs_to : { type: 'string', required: true, defaultsTo: 0 },
signin_count : { type: 'integer', required: true, defaultsTo: 1 },
status_active : { type: 'boolean', required: true, defaultsTo: false },
last_signin_at : { type: 'datetime', defaultsTo: function (){ return new Date(); } },
last_signin_ip : { type: 'string', defaultsTo: '0.0.0.0' },
// Add a reference to Forms collection
forms:
{
collection: 'form',
via: 'user',
through: 'userhasform'
// dominant: true
}
}
};
Form.js
module.exports = {
schema: true,
tableName: 'forms',
attributes:
{
name : { type: 'string', required: true, unique: true },
creator : { type: 'string', unique: false },
sequence: { type: 'integer', autoIncrement: true },
// Add a reference to the owners Users
owners: {
collection: 'user',
via: 'form',
through: 'userhasform'
}
}
};
UserHasForm.js
module.exports = {
schema: true,
tableName: 'users_have_forms',
attributes:
{
to_edit : { type: 'boolean' },
to_delete : { type: 'boolean' },
user : { model: 'User', foreignKey: true, columnName: 'user_id' },
form : { model: 'Form', foreignKey: true, columnName: 'form_id' }
}
};
FormController.js
Still the same as in the question
I hope it could be useful for anybody. And once again thanks to # Alexander Arutinyants for your support!
Any question, please leave a comment!