sequelize model exclude subfield within a jsonb field - node.js

I have a postgresql table structured with a jsonb field named external_data:
external_data: {a: 1, b:2, c:3}
I know that in sequelize model definitions, you can exclude a field by including in the options properties a defaultScope like this:
{defaultScope: {attributes: { exclude: ['external_data'] }}
When I do that to exclude the entire field, it works, i.e. external_data doesn't show up in returned results. However, I'd like to exclude a specific subfield. I've tried exclude: ['external_data.b'] but that doesn't seem to work.
Does sequelize allow excluding subfields within jsonb fields? And if so, what's the proper format of the exclude attribute to do it?

From the docs: https://sequelize.org/v5/manual/scopes.html
Scopes are defined in the model definition and can be finder objects, or functions returning finder objects - except for the default scope, which can only be an object
So, you can define the scope via a function that returns the finder objects so that you can implement the complex scope.
E.g.
import { sequelize } from '../../db';
import { Model, DataTypes, Op } from 'sequelize';
class TableA extends Model {}
TableA.init(
{
external_data: DataTypes.JSONB,
},
{
sequelize,
modelName: 'table_a',
defaultScope: {
attributes: { exclude: ['external_data'] },
},
scopes: {
exclude(subField) {
return {
where: {
external_data: {
[subField]: {
[Op.eq]: null,
},
},
},
};
},
},
},
);
(async function test() {
try {
// create tables
await sequelize.sync({ force: true });
// seed
await TableA.bulkCreate([
{ external_data: { a: 1, b: 2, c: 3 } },
{ external_data: { a: 10, c: 30 } },
{ external_data: { a: 100 } },
]);
// test
// test case 1: exclude subfield "b"
const result1 = await TableA.scope({ method: ['exclude', 'b'] }).findAll({ raw: true });
console.log('result1:', result1);
// test case 2: exclude subfield "c"
const result2 = await TableA.scope({ method: ['exclude', 'c'] }).findAll({ raw: true });
console.log('result2:', result2);
} catch (error) {
console.log(error);
} finally {
await sequelize.close();
}
})();
The execution results:
Executing (default): DROP TABLE IF EXISTS "table_a" CASCADE;
Executing (default): DROP TABLE IF EXISTS "table_a" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "table_a" ("id" SERIAL , "external_data" JSONB, PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'table_a' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): INSERT INTO "table_a" ("id","external_data") VALUES (DEFAULT,'{"a":1,"b":2,"c":3}'),(DEFAULT,'{"a":10,"c":30}'),(DEFAULT,'{"a":100}') RETURNING *;
Executing (default): SELECT "id", "external_data" FROM "table_a" AS "table_a" WHERE ("table_a"."external_data"#>>'{b}') IS NULL;
result1: [ { id: 2, external_data: { a: 10, c: 30 } },
{ id: 3, external_data: { a: 100 } } ]
Executing (default): SELECT "id", "external_data" FROM "table_a" AS "table_a" WHERE ("table_a"."external_data"#>>'{c}') IS NULL;
result2: [ { id: 3, external_data: { a: 100 } } ]
check the database:
node-sequelize-examples=# select * from "table_a";
id | external_data
----+--------------------------
1 | {"a": 1, "b": 2, "c": 3}
2 | {"a": 10, "c": 30}
3 | {"a": 100}
(3 rows)
Dependencies versions: "sequelize": "^5.21.3", postgres:9.6
source code: https://github.com/mrdulin/node-sequelize-examples/tree/master/src/examples/stackoverflow/61053931

Related

left outer join with custom ON condition sequelize

I'm using sequelize, DB as Postgres
my students table as ( id, name, dept_id ) columns.
my departments table as ( id, dname, hod) columns
My Association while looks like this
Student.hasOne(models.Department, {
foreignKey: 'id',
as : "role"
});
I want to get a student with a particular id and his department details. By using sequelize I wrote a query like below
Student.findOne({
where: { id: id },
include: [{
model: Department,
as:"dept"
}],
})
FYI with this includes option in findOne, it is generated a left outer join query as below
SELECT "Student"."id", "Student"."name", "Student"."dept_id", "dept"."id" AS "dept.id", "dept"."dname" AS "dept.dname", "dept"."hod" AS "dept.hod", FROM "students" AS "Student"
LEFT OUTER JOIN "departments" AS "dept"
ON "Student"."id" = "dept"."id"
WHERE "Student"."id" = 1
LIMIT 1;
My expected Output should be
{
id: 1,
name: "bod",
dept_id: 4,
dept: {
id: 4,
dname: "xyz",
hod: "x"
}
}
but I'm getting
{
id: 1,
name: "bod",
dept_id: 4,
dept: {
id: 1,
dname: "abc",
hod: "a"
}
}
so how to I change ON condition to
ON "Student"."dept_id" = "dept"."id"
thank you in advance
Student.hasOne(models.Department, {
foreignKey: 'dept_id', // fixed
as : "role"
});

Sequelize Update with Object

I have a code using sequelize to update one record and then return this updated record:
const companyId = req.params.id
const companyNewDetail = req.body
console.log("companyNewDetail", companyNewDetail)
await Company.update(companyNewDetail, {
where: {
companyId,
},
})
const company = await Company.findOne({
where: {
companyId,
},
})
res.status(200).send({ status: 0, data: company })
It is working but I have to seperate into two query statements. Is there a way I can mix them together? I want to pass the update parameter with a object rather than destructuring the object and assign to the instance one by one.
The returning option of Model.update still only supports PostgreSQL for sequelize v6.
For example:
import { sequelize } from '../../db';
import { Model, DataTypes, Sequelize } from 'sequelize';
// const sequelize = new Sequelize('sqlite::memory:');
class Company extends Model {}
Company.init(
{
companyId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
name: DataTypes.STRING,
},
{ sequelize, tableName: 'companies' },
);
(async function test() {
try {
await sequelize.sync({ force: true });
// seed
await Company.create({ name: 'google' });
// test
const companyId = 1;
const companyNewDetail = { name: 'reddit' };
const result = await Company.update(companyNewDetail, {
where: {
companyId,
},
returning: true,
});
console.log(result);
} catch (error) {
console.log(error);
} finally {
await sequelize.close();
}
})();
If you use postgres dialect, you will get the following result:
Executing (default): DROP TABLE IF EXISTS "companies" CASCADE;
Executing (default): DROP TABLE IF EXISTS "companies" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "companies" ("companyId" SERIAL , "name" VARCHAR(255), PRIMARY KEY ("companyId"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'companies' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): INSERT INTO "companies" ("companyId","name") VALUES (DEFAULT,$1) RETURNING *;
Executing (default): UPDATE "companies" SET "name"=$1 WHERE "companyId" = $2 RETURNING *
[
1,
[
Company {
dataValues: [Object],
_previousDataValues: [Object],
_changed: {},
_modelOptions: [Object],
_options: [Object],
isNewRecord: false
}
]
]
The first element of the result array is the number of affected rows for the updating operation. The second element is the sequelize model instances of updated rows.
For sqlite3, you will get:
Executing (default): DROP TABLE IF EXISTS `companies`;
Executing (default): DROP TABLE IF EXISTS `companies`;
Executing (default): CREATE TABLE IF NOT EXISTS `companies` (`companyId` INTEGER PRIMARY KEY AUTOINCREMENT, `name` VARCHAR(255), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL);
Executing (default): PRAGMA INDEX_LIST(`companies`)
Executing (default): INSERT INTO `companies` (`companyId`,`name`,`createdAt`,`updatedAt`) VALUES (NULL,$1,$2,$3);
Executing (default): UPDATE `companies` SET `name`=$1,`updatedAt`=$2 WHERE `companyId` = $3
[ undefined, 1 ]
So, you need to do an additional query for other databases after updating the rows in the table.

sequelize methods from association fooInstance.getBars() returning a wrong value

I've got 2 models with a many-to-many association through another model. By default, Sequelize creates instance methods for both models as you all may know (https://sequelize.org/master/manual/assocs.html#special-methods-mixins-added-to-instances).
My problem is that the fooInstance.getBars() method and fooInstance.countBars() both return the wrong number of records.
The database was setup using sequelize migration files.
The 3 models are below.
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define(
"User",
{
firstName: DataTypes.STRING
},
{}
);
User.associate = function(models) {
// associations can be defined here
User.belongsToMany(models.Week, {
through: models.Roster,
foreignKey: {
name: "weekId"
}
});
};
return User;
};
"use strict";
module.exports = (sequelize, DataTypes) => {
const Week = sequelize.define(
"Week",
{
date: {
type: DataTypes.DATE,
allowNull: false,
unique: true
}
},
{}
);
Week.associate = function(models) {
// associations can be defined here
Week.belongsToMany(models.User, {
through: models.Roster,
foreignKey: {
name: "userId",
allowNull: true
}
});
};
return Week;
};
"use strict";
module.exports = (sequelize, DataTypes) => {
const Roster = sequelize.define(
"Roster",
{
weekId: {
type: DataTypes.INTEGER,
allowNull: false,
unique: false
},
userId: {
type: DataTypes.INTEGER,
allowNull: true,
unique: false
}
},
{}
);
Roster.associate = function(models) {
// associations can be defined here
};
return Roster;
};
Before I test out the methods, I created 1 record in weeks and 5 records in users then I created 5 associations using 5 Roster.create() in rosters.
When I do a query in my routes file like this await Week.getUsers(), instead of returning 5 users in an array, it returned 1 in an array. Similarly, the await Week.countUsers() code returned 1 instead of 5.
Please help!
Please let me know if I miss any important information.
Thank you!
Like the docs says:
When an association is defined between two models, the instances of those models gain special methods to interact with their associated counterparts.
You are trying to call these special methods on Model class. Here is a working example:
import { sequelize } from '../../db';
import { Model, DataTypes, BelongsToManyGetAssociationsMixin, BelongsToManyCountAssociationsMixin } from 'sequelize';
class User extends Model {}
User.init(
{
firstName: DataTypes.STRING,
},
{ sequelize, modelName: 'User' },
);
class Week extends Model {
public getUsers!: BelongsToManyGetAssociationsMixin<User>;
public countUsers!: BelongsToManyCountAssociationsMixin;
}
Week.init(
{
date: {
type: DataTypes.DATE,
allowNull: false,
unique: true,
},
},
{ sequelize, modelName: 'Week' },
);
class Roster extends Model {}
Roster.init(
{
weekId: {
type: DataTypes.INTEGER,
allowNull: false,
unique: false,
},
userId: {
type: DataTypes.INTEGER,
allowNull: true,
unique: false,
},
},
{ sequelize, modelName: 'Roster' },
);
User.belongsToMany(Week, { through: Roster, foreignKey: { name: 'weekId' } });
Week.belongsToMany(User, { through: Roster, foreignKey: { name: 'userId', allowNull: true } });
(async function test() {
try {
// create tables
await sequelize.sync({ force: true });
// seed
const week = await Week.create(
{
date: new Date(),
Users: [
{ firstName: 'james' },
{ firstName: 'elsa' },
{ firstName: 'tim' },
{ firstName: 'lee' },
{ firstName: 'jasmine' },
],
},
{ include: [User] },
);
// test
const count = await week.countUsers();
console.log('count:', count);
const users = await week.getUsers();
console.log('users count:', users.length);
} catch (error) {
console.log(error);
} finally {
await sequelize.close();
}
})();
The execution results:
Executing (default): DROP TABLE IF EXISTS "Roster" CASCADE;
Executing (default): DROP TABLE IF EXISTS "Week" CASCADE;
Executing (default): DROP TABLE IF EXISTS "User" CASCADE;
Executing (default): DROP TABLE IF EXISTS "User" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "User" ("id" SERIAL , "firstName" VARCHAR(255), PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'User' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): DROP TABLE IF EXISTS "Week" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "Week" ("id" SERIAL , "date" TIMESTAMP WITH TIME ZONE NOT NULL UNIQUE, PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'Week' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): DROP TABLE IF EXISTS "Roster" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "Roster" ("weekId" INTEGER NOT NULL REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE, "userId" INTEGER REFERENCES "Week" ("id") ON DELETE CASCADE ON UPDATE CASCADE, UNIQUE ("weekId", "userId"), PRIMARY KEY ("weekId","userId"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'Roster' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): INSERT INTO "Week" ("id","date") VALUES (DEFAULT,$1) RETURNING *;
Executing (default): INSERT INTO "User" ("id","firstName") VALUES (DEFAULT,$1) RETURNING *;
Executing (default): INSERT INTO "User" ("id","firstName") VALUES (DEFAULT,$1) RETURNING *;
Executing (default): INSERT INTO "User" ("id","firstName") VALUES (DEFAULT,$1) RETURNING *;
Executing (default): INSERT INTO "User" ("id","firstName") VALUES (DEFAULT,$1) RETURNING *;
Executing (default): INSERT INTO "User" ("id","firstName") VALUES (DEFAULT,$1) RETURNING *;
Executing (default): INSERT INTO "Roster" ("weekId","userId") VALUES ($1,$2) RETURNING *;
Executing (default): INSERT INTO "Roster" ("weekId","userId") VALUES ($1,$2) RETURNING *;
Executing (default): INSERT INTO "Roster" ("weekId","userId") VALUES ($1,$2) RETURNING *;
Executing (default): INSERT INTO "Roster" ("weekId","userId") VALUES ($1,$2) RETURNING *;
Executing (default): INSERT INTO "Roster" ("weekId","userId") VALUES ($1,$2) RETURNING *;
Executing (default): SELECT COUNT("User"."id") AS "count" FROM "User" AS "User" INNER JOIN "Roster" AS "Roster" ON "User"."id" = "Roster"."weekId" AND "Roster"."userId" = 1;
count: 5
Executing (default): SELECT "User"."id", "User"."firstName", "Roster"."weekId" AS "Roster.weekId", "Roster"."userId" AS "Roster.userId" FROM "User" AS "User" INNER JOIN "Roster" AS "Roster" ON "User"."id" = "Roster"."weekId" AND "Roster"."userId" = 1;
users count: 5
check the database:
node-sequelize-examples=# select * from "User";
id | firstName
----+-----------
1 | james
2 | elsa
3 | tim
4 | lee
5 | jasmine
(5 rows)
node-sequelize-examples=# select * from "Week";
id | date
----+---------------------------
1 | 2020-04-14 01:56:56.55+00
(1 row)
node-sequelize-examples=# select * from "Roster";
weekId | userId
--------+--------
1 | 1
2 | 1
3 | 1
4 | 1
5 | 1
(5 rows)
Dependencies versions: "sequelize": "^5.21.3", postgres:9.6
source code: https://github.com/mrdulin/node-sequelize-examples/tree/master/src/examples/stackoverflow/60805725

How can I join same table using sequalizer?

I am using sequalizer first time and stuck in a situation
I have a table categories as below
I need details like
[{
"id" : 7,
"name": "Mobile Cover",
parent: {
"id": 1
"name": "Mobile",
}
},
{
"id" : 9,
"name": "Mobile Glass",
parent: {
"id": 1
"name": "Mobile",
}
},
{
"id" : 8,
"name": "Knife",
parent: {
"id": 4
"name": "Kitchenware",
}
}]
I try with include but it's not working
const result = await category.findAll({
where: {
parentId: {
[Op.ne]: null
}
},
include: {
model: category,
where: {
'id': 'category.parentId'
}
},
order: [
["createdAt", "DESC"],
],
});
it's returning error
SequelizeDatabaseError: table name "categories" specified more than
once
Is there any way to do this?
Sequelize version: "sequelize": "^5.21.3". Here is a working example:
index.ts:
import { sequelize } from '../../db';
import Sequelize, { Model, DataTypes, Op } from 'sequelize';
class Category extends Model {}
Category.init(
{
id: {
primaryKey: true,
autoIncrement: true,
allowNull: false,
type: DataTypes.INTEGER,
},
name: DataTypes.STRING,
},
{ sequelize, modelName: 'categories' },
);
Category.belongsTo(Category, { foreignKey: 'parentId', as: 'parent', targetKey: 'id' });
(async function test() {
try {
await sequelize.sync({ force: true });
// seed
const parent1 = { id: 1, name: 'Mobile' };
const parent2 = { id: 4, name: 'Kitchenware' };
await Category.bulkCreate([parent1, parent2]);
await Category.bulkCreate([
{ id: 7, name: 'Mobile Cover', parentId: parent1.id },
{ id: 8, name: 'Knife', parentId: parent2.id },
{ id: 9, name: 'Mobile Glass', parentId: parent1.id },
]);
// test
const result = await Category.findAll({
include: [
{
model: Category,
required: true,
as: 'parent',
attributes: ['id', 'name'],
},
],
attributes: ['id', 'name'],
raw: true,
});
console.log('result: ', result);
} catch (error) {
console.log(error);
} finally {
await sequelize.close();
}
})();
The execution results:
Executing (default): DROP TABLE IF EXISTS "categories" CASCADE;
Executing (default): DROP TABLE IF EXISTS "categories" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "categories" ("id" SERIAL , "name" VARCHAR(255), "parentId" INTEGER REFERENCES "categories" ("id") ON DELETE SET NULL ON UPDATE CASCADE, PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'categories' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): INSERT INTO "categories" ("id","name") VALUES (1,'Mobile'),(4,'Kitchenware') RETURNING *;
Executing (default): INSERT INTO "categories" ("id","name","parentId") VALUES (7,'Mobile Cover',1),(8,'Knife',4),(9,'Mobile Glass',1) RETURNING *;
Executing (default): SELECT "categories"."id", "categories"."name", "parent"."id" AS "parent.id", "parent"."name" AS "parent.name" FROM "categories" AS "categories" INNER JOIN "categories" AS "parent" ON "categories"."parentId" = "parent"."id";
result: [ { id: 7,
name: 'Mobile Cover',
'parent.id': 1,
'parent.name': 'Mobile' },
{ id: 8,
name: 'Knife',
'parent.id': 4,
'parent.name': 'Kitchenware' },
{ id: 9,
name: 'Mobile Glass',
'parent.id': 1,
'parent.name': 'Mobile' } ]
Check the data records in the database:
node-sequelize-examples=# select * from "categories";
id | name | parentId
----+--------------+----------
1 | Mobile |
4 | Kitchenware |
7 | Mobile Cover | 1
8 | Knife | 4
9 | Mobile Glass | 1
(5 rows)
You need to define an association as follows -
Category.belongsTo(Category, {
foreignKey: "parentID",
targetKey: "id"
});
Before using include you need to define associations on the basis of their relations. Sequelize has all traditional types of relationships like hasMany, BelogTo, etc.
furthermore check out the link: https://sequelize.org/master/manual/associations.html

Associations not working for Sequelize

I run the below mutation first, creates the fish, I also created a river all ready. Why are rivers and fishes empty?
Graphql:
query {
fishes {
name
species
rivers {
name
}
}
river(id: 1) {
name
fishes {
name}
}
}
# mutation {
# createFish (name: "Orange-Vall Smallmouth Yellowfish", species: "Labeobarbus aeneus", riverId: 1) {
# name
# rivers {
# name
# }
# }
# }
The results are below:
{
"data": {
"fishes": [
{
"name": "Orange-Vall Smallmouth Yellowfish",
"species": "Labeobarbus aeneus",
"rivers": []
}
],
"river": {
"name": "Orange River",
"fishes": []
}
}
}
Below are the two models:
const Fish = sequelize.define('fish', schema);
Fish.associate = models => {
Fish.belongsToMany(models.River, { through: 'RiverFish' });
};
const River = sequelize.define('river', schema);
River.associate = models => {
River.belongsToMany(models.Fish, { through: 'RiverFish', as: 'Fishes' });
};
Part of the graphql query:
River: {
fishes: river => river.getFishes(), },
Fish: {
rivers: fish => fish.getRivers(), },
Sequelize logs:
Executing (default): CREATE TABLE IF NOT EXISTS `fishes` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` VARCHAR(255), `species` VARCHAR(255) DEFAULT NULL, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL);
Connection has been established successfully.
Executing (default): PRAGMA INDEX_LIST(`fishes`)
Executing (default): CREATE TABLE IF NOT EXISTS `rivers` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` VARCHAR(255), `alternative` VARCHAR(255) DEFAULT NULL, `geojson` JSON, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL);
Executing (default): PRAGMA INDEX_LIST(`rivers`)
Executing (default): CREATE TABLE IF NOT EXISTS `RiverFish` (`createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `fishId` INTEGER NOT NULL REFERENCES `fishes` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, `riverId` INTEGER NOT NULL REFERENCES `rivers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY (`fishId`, `riverId`));
Executing (default): PRAGMA INDEX_LIST(`RiverFish`)
Executing (default): PRAGMA INDEX_INFO(`sqlite_autoindex_RiverFish_1`)
EDIT
If I change my models the results are working from the River side of things:
River.hasMany(models.Fish, { as: 'Fishes' });
Fish.belongsToMany(models.River, { through: 'RiverFish', as: 'Rivers' });
{
"data": {
"fishes": [
{
"id": "1",
"name": "Orange-Vall Smallmouth Yellowfish",
"species": "Labeobarbus aeneus",
"rivers": []
}
],
"river": {
"name": "Orange River",
"fishes": [
{
"name": "Orange-Vall Smallmouth Yellowfish"
}
]
},
"rivers": null
}
UPDATE
I believe this could be the issue. I have this in a my models directory:
import Fish from './Fish';
import River from "./River";
const models = {
Fish,
River
};
Object.keys(models).forEach(name => {
const model = models[name];
if (typeof model.associate === 'function') {
model.associate(models);
}
});
export {
Fish, River,
};

Resources