Relation does not exist in adonis/node.js - node.js

I have two tables: book and book_units as you can see below:
class BookSchema extends Schema {
up () {
this.create('books', (table) => {
table.increments()
table.string('code').notNullable().unique()
table.string('description')
table.string('authors')
table.boolean('status').defaultTo(false)
table.integer('user_id').references('id').inTable('users')
table.timestamps()
})
}
}
class BookUnitSchema extends Schema {
up () {
this.create('book_unit', (table) => {
table.increments()
table.integer('book_id').references('id').inTable('books').notNullable()
table.integer('unit').notNullable().unique()
table.integer('sequence').unique()
table.string('description')
table.integer('qt_question')
table.boolean('status').defaultTo(false)
table.integer('user_id').references('id').inTable('users')
table.timestamps()
})
}
}
In the Book model, i defined a relationship with book_units:
class Book extends Model {
book_units () {
return this.hasMany('App/Models/BookUnit')
}
}
And in the Book Unit Model:
class BookUnit extends Model {
book () {
return this.belongsTo('App/Models/Book')
}
}
I'm trying to make a insert using postman in the book_unit using this json:
{
"book_id": 1,
"unit": 1,
"sequence": 1,
"description": "UNIT_01_GRAMMAR",
"qt_question": 5,
"status": false
}
But i'm receiving:
insert into "book_units" ("book_id", "created_at", "description",
"qt_question", "sequence", "status", "unit", "updated_at", "user_id")
values ($1, $2, $3, $4, $5, $6, $7, $8, $9) returning "id" - relation
"book_units" does not exist
This book with id 1 exist in database. Why i'm receiving this error?

I tested your code.
I noticed this problem:
By default the AdonisJS CLI creates a table with the name : book_units (you code : book_unit) command: > adonis make:migration BookUnit
I solved the problem with (App/Models/BookUnit):
class BookUnit extends Model {
static get table() {
return 'book_unit'
} // Model table name
...
OR
change
this.create('book_unit', (table) => {
by
this.create('book_units', (table) => {
Explanation
Models and migrations are not linked. If you change the name of the table in the migration, it's necessary to pass it on to the model.
Full code
schemas :
class BookUnitSchema extends Schema {
up() {
this.create('book_unit', (table) => {
table.increments()
table.integer('book_id').references('id').inTable('books').notNullable()
table.integer('unit').notNullable().unique()
table.integer('sequence').unique()
table.string('description')
table.integer('qt_question')
table.boolean('status').defaultTo(false)
table.integer('user_id').references('id').inTable('users')
table.timestamps()
})
}
down() {
this.drop('book_units')
}
}
//=====================================
class BookSchema extends Schema {
up() {
this.create('books', (table) => {
table.increments()
table.string('code').notNullable().unique()
table.string('description')
table.string('authors')
table.boolean('status').defaultTo(false)
table.integer('user_id').references('id').inTable('users')
table.timestamps()
})
}
down() {
this.drop('books')
}
}
Models :
class BookUnit extends Model {
static get table() {
return 'book_unit'
}
book() {
return this.belongsTo('App/Models/Book')
}
}
//==============================
class Book extends Model {
book_units() {
return this.hasMany('App/Models/BookUnit')
}
}
Test :
var data = {
"book_id": 1,
"unit": 1,
"sequence": 1,
"description": "UNIT_01_GRAMMAR",
"qt_question": 5,
"status": false
}
const bookUnit = await BookUnit.create(data)
Result:
Test config :
SQLite
Don't hesitate if you need more information.

Try doing this
table.integer('book_id').unsigned().references('id').inTable('books').notNullable()
next thing in your api its better to fetch the book by its id and then use create method.
let book = await Book.findBy('id',params.id)//your book id from your req object
book.book_units().create({
"book_id": 1,
"unit": 1,
"sequence": 1,
"description": "UNIT_01_GRAMMAR",
"qt_question": 5,
"status": false
})

Related

how get dependent dropdown data in node with postgres

I have done following thing, using nodejs exoress with postgresql. For this api my input will be country id, modelname of country & for left join another model name im
{
"id": 1,
"module": "state_master",
"leftJoinmodule": "country_master"
}
exports.getStateDataByCountryId = async (req, res) => {
if (!req.body.module) {
return response.fail(res, "Model Name is Required", "");
}
const id = req.body.id;
var module = req.body.module;
var leftJoinmodule = req.body.leftJoinmodule;
console.log(leftJoinmodule)
if (Model[module]) {
Model[module]
.findAll({
raw: true,
where: {
country_id: id,
active: 1,
},
include: [{
model: Model.leftJoinmodule,
as: 'country'
},]
// include: [{
// model: Model.leftJoinmodule,
// as: 'country',
// where: {
// id: id
// }
// }]
})
.then((allStateMasterData) => {
return response.success(res, "All State Data", allStateMasterData);
})
.catch((err) => {
return response.catchError(res, err.message, "", module);
});
} else {
return response.fail(res, "Invalide Model Name", "");
}
};
getting below error
{
"status": 500,
"code": 0,
"message": "Include unexpected. Element has to be either a Model, an Association or an object.",
"data": ""
}
anyone plz help on this issue

Node.js - How to get associated model data using graphql?

In Node.js app, I am using graphql to get the list of data. I have created two models called School and Grade. Association for these models like School has many Grades and Grade belongs to School.
While querying I am getting null value for associated model.
In model school.js,
module.exports = (sequelize, Sequelize) => {
const School = sequelize.define("school", {
name: {
type: Sequelize.STRING,
},
email: {
type: Sequelize.STRING,
},
});
School.associate = function (models) {
School.hasMany(models.Grade, { foreignKey: "school_id" });
};
return School;
};
In typeDefs.graphql,
type Query {
getSchoolDetails: [School]
getSchoolDetail(id: ID!): School
getGradeDetails: [Grade]
}
type School {
id: ID!
name: String
email: String
grades: [Grade]
}
type Grade {
id: ID!
school_id: ID!
name: String
school: School
}
In resolvers.js,
const Query = {
getSchoolDetails: async () => {
try {
const schools = await school.findAll();
return schools;
} catch (err) {
console.log(err);
}
},
getSchoolDetail: async (root, { id }) => {
try {
const scl = await school.findByPk(id);
return scl;
} catch (err) {
console.log(err);
}
},
getGradeDetails: async () => {
try {
const grades = await grade.findAll({});
return grades;
} catch (err) {
console.log(err);
}
},
}
In playground when I query like,
query {
getSchoolDetails{
id
name
email
grades{
name
}
}
}
Output for this is,
{
"data": {
"getSchoolDetails": [
{
"id": "1",
"name": "Rotary West School",
"email": "rotary#gmail.com",
"grades": null
},
{
"id": "2",
"name": "Excel Public School",
"email": "excel#gmail.com",
"grades": null
},
]
}
Same way when I query to get Grades will get school as null. I am learning nodejs relations with graphql, please help me to solve this.
You have to use include with your queries in resolvers.js file like below
getSchoolDetails: async () => {
try {
const schools = await school.findAll({
include: [{ model: Grade }],
});
return schools;
} catch (err) {
console.log(err);
}
},
This Will get all the grades associated with schools
And if you want to include school with grade you have to associate grade with school using Grades belongsTo school

How to implement pagination in graphql which returns pagination metadata along with dataset

Currently i use graphql default pagination, that is by using limit offset (code given below) . which is working fine. but instead of the team list how can we include pagination metadata. and return the pagination metadata along with this. I use sequalize to fetch the data
type Query {
allTeams(page:Int, pageSize:Int): [Team]
}
type Team {
id: Int
name: String
}
//resolver with pagination
const paginate = ( page, pageSize ) => {
var offset = page * pageSize;
var limit = pageSize;
return {
offset,
limit,
};
};
export const resolvers = {
Query: {
allTeams: async (obj, args, context, info ) => Teams.findAll(
paginate( args.page, args.pageSize ),
),
},
}
The above code will only return the list of teams .
Is there any way i can return a the output as which contains team list and pagination details
{
"data": {
"allTeams": [
{
"id": 4,
"name": "Team created from postman",
},
{
"id": 5,
"name": "Team created from postman",
}
]
},
"pageInfo": {
"currentPage": 2,
"perPage": 2,
"itemCount": 4,
"pageCount": 2,
"hasPreviousPage": true,
"hasNextPage": false
}
}
Yep, you'll just need to add the pagination metadata to your schema and provide the data in your resolvers. So for the output you're looking to achieve, the schema would look like:
type Query {
teams(page:Int, pageSize:Int): TeamsConnection
}
type TeamsConnection {
results: [Team]
pageInfo: PageInfo
}
type Team {
id: Int
name: String
}
type PageInfo {
currentPage: Int
perPage: Int
itemCount: Int
pageCount: Int
hasPreviousPage: Boolean
hasNextPage: Boolean
}
Your resolver would then need to return the new shape of the response data. So something like:
export const resolvers = {
Query: {
allTeams: async (obj, args, context, info ) => {
const results = await Teams.findAll(
paginate(args.page, args.pageSize),
);
return {
results,
pageInfo: {...}
}
}
}
}

Save data with relation (Nodejs / loopback 4 / mongoDB)

I can not post data json with relation object.
I use mongoDB.
I have 3 table: table_1, table_2, table_3.
I create relation EmbedsMany and EmbedsOne:
- table_2 EmbedsOne table_1.
- table_2 EmbedsMany table_3.
I don't know create post data json to create a new item of table_2 with item of table_1.
import { ..., embedsMany, embedsOne } from '#loopback/repository';
import { Model1, Mode1WithRelations } from './model-1.model';
import { Model3, Model3WithRelations } from './model-2.model';
#model({
settings: {
strictObjectIDCoercion: true,
mongodb: {
collection: 'table_2'
}
}
})
export class Model2 extends Entity {
#property({
type: 'string',
id: true,
mongodb: {
dataType: 'ObjectID' // or perhaps 'objectid'?
}
})
id?: string;
#embedsMany(() => Model3)
model3?: Model3[];
#embedsOne(() => Model1)
model1: Model1;
}
export interface Model2Relations {
// describe navigational properties here
model3?: Model3WithRelations[];
model1: Mode1WithRelations;
}
export type Model2WithRelations = Model2 & Model2Relations;
Repository model 2
import { DefaultCrudRepository } from '#loopback/repository';
import { Model2, Model2Relations } from '../models';
import { DbDataSource } from '../datasources';
import { inject } from '#loopback/core';
export class Model2Repository extends DefaultCrudRepository<
Model2,
typeof Model2.prototype.id,
Model2Relations
> {
constructor(
#inject('datasources.DB') dataSource: DbDataSource,
) {
super(Model2, dataSource);
}
}
Json data post
{
"address": "string",
"status": 1,
"createdAt": "2019-08-04T03:57:12.999Z",
"updatedAt": "2019-08-04T03:57:12.999Z",
"model1": {
"id": "5d465b4cd91e484250d1e54b" /* id of exist item in table_1 */
}
}
Controller is generate by lb4 controller
Expected:
- Item is save success into table_2 with EmbedsOne item of table_1.
Actual:
- Error:
{
"error": {
"statusCode": 422,
"name": "ValidationError",
"message": "The `Model2` instance is not valid. Details: `model1` is not defined in the model (value: undefined).",
"details": {
"context": "Model2",
"codes": {
"project": ["unknown-property"]
},
"messages": {
"model1": ["is not defined in the model"]
}
}
}
}
TL;DR
According to the Loopback 4 team,
#embedsOne
#embedsMany
#referencesOne
#referencesMany
has not implemented yet (2019-Sep-03). (See docs or github)
But I found these decorators and their classes on the sourcecode
So, hopefully, we have to wait untill the implementation is complete. I'll try to update this answer if I got anything new.

Querying nested object using $find by applying conditions in Mongodb

This is my json object
{
"account_id" : "1",
"sections" : [
"name" : "sec1",
"label" : {
"label1" : "text1",
"label2" : "text2"
}
},
"name" : "sec2",
"label" : {
"label3" : "text3",
"label4" : "text4",
"label5" : "text5"
}
},
]
}
So in this json I wanted to query the label object where sector= sec1. I have used the below code but it didn't work.
var getData = (db, query) => {
return db
.collection(TABLE_NAME)
.find(query, { account_id: { sections: { label: 1 } } })
.toArrayAsync();
};
var dataList = (db, event) => {
let dataQuery = {
account_id: id,
'sections.name': event.params.section
};
return getData(db, dataQuery);
};
module.exports.getData = (event, cb) => {
return using(connectDatabase(), db => {
return dataList (db, event);
}).then(data => cb(null, responseObj(data, 200)), err =>
cb(responseObj(err, 500)));
};
Could someone kindly help me? Thanks inadvance.
Try something like this. use $project, we can selectively remove or retain field and we can reassign existing field values and derive entirely new values. after projecting the labels and name do a $match to extract the document by name. One thing to notice is that by using $project,it will automatically assign the document's _id.
var dataList = (db, event) => {
return db
.collection(TABLE_NAME)
.aggregate([
{
$match: { account_id: your_id }
},
{
$unwind: '$sections'
},
{
$project:{labels:'$sections.label',name:'$sections.name'}
},
{
$match:{name:section_name}
}]).toArray();
};
You have to use aggregate method with $unwind syntax to find item in array of object.
var dataList = (db, event) => {
return db
.collection(TABLE_NAME)
.aggregate([
{
$match: {
account_id: id,
}
},
{ $unwind: "$comments" },
{
$match: {
'name': event.params.section
}
}
])
.toArrayAsync();
};
Result:
[{
"account_id": "1",
"sections": {
"name": "sec2",
"label": {
"label3": "text3",
"label4": "text4",
"label5": "text5"
}
}
}]

Resources