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
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
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
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: {...}
}
}
}
}
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.
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"
}
}
}]