Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Sequelize create with nested objects and relations

I have 3 models. User, Item and Location.

User.hasMany(Item)
Location.hasMany(Item)
Item.belongsTo(User)
Item.belongsTo(Location)

this runs, but does not create the location foreign key nor location row in locations table.

    models.User.create(
    {
      username: 'ddavids',
      email: '[email protected]',
      password: '12345678',
      items: [
        {
          itemName: 'Good Book',
          orderDate: '2020-01-20',
          locations: { locationName: 'floor' }
        },
        {
          itemName: 'Bad Book',
          orderDate: '2020-01-21',
          locations: { locationName: 'shelf' }
        }
      ]
    },
    {
      include: [{ model: models.Item, include: [models.Location] }]
    }
   )

This creates the items and locations correctly but obviously not under a user.

    models.Location.create(
    {
      locationName: 'floor',
      items: [
        {
          itemName: 'Good Book',
          orderDate: '2020-01-20',
          locations: { locationName: 'floor' }
        },
        {
          itemName: 'Bad Book',
          orderDate: '2020-01-21',
          locations: { locationName: 'shelf' }
        }
      ]
    },
    { include: [models.Item] }
   )

What I can't figure out is if my relations are the wrong way to go about this or if its a limitation of create and I should move on or what. My end goal will be something along the lines of.

 User.hasMany(Order)
 Order.belongsTo(User)
 Order.hasMany(Item)
 Item.belongsTo(Order)
 Location.hasMany(Item)
 Item.belongsTo(location)
 Supplier.hasMany(Item)
 Item.belongsTo(Supplier)

I am currently using create just to create some fake data for when I make changes. So if there is a better way to seed the database that would be my end goal.

like image 925
James Avatar asked Oct 15 '22 06:10

James


1 Answers

Because of the association of Location and Item models is one-to-many. So you should change the

locations: { locationName: 'floor' } to location: { locationName: 'floor' }. The location of Item should not be plural. It means each item belongs to one location.

Here is the working example:

index.ts:

import { sequelize } from '../../db';
import { Model, DataTypes } from 'sequelize';

class User extends Model {}
User.init(
  {
    username: DataTypes.STRING,
    email: DataTypes.STRING,
    password: DataTypes.STRING,
  },
  { sequelize, modelName: 'user' },
);

class Location extends Model {}
Location.init(
  {
    locationName: DataTypes.STRING,
  },
  { sequelize, modelName: 'location' },
);

class Item extends Model {}
Item.init(
  {
    itemName: DataTypes.STRING,
    orderDate: DataTypes.STRING,
  },
  { sequelize, modelName: 'item' },
);

User.hasMany(Item);
Location.hasMany(Item);
Item.belongsTo(User);
Item.belongsTo(Location);

(async function test() {
  try {
    await sequelize.sync({ force: true });
    await User.create(
      {
        username: 'ddavids',
        email: '[email protected]',
        password: '12345678',
        items: [
          {
            itemName: 'Good Book',
            orderDate: '2020-01-20',
            location: { locationName: 'floor' },
          },
          {
            itemName: 'Bad Book',
            orderDate: '2020-01-21',
            location: { locationName: 'shelf' },
          },
        ],
      },
      {
        include: [{ model: Item, include: [Location] }],
      },
    );
  } catch (error) {
    console.log(error);
  } finally {
    await sequelize.close();
  }
})();

After execution above code, check the data records in the database:

node-sequelize-examples=# select * from "user";
 id | username |      email      | password
----+----------+-----------------+----------
  1 | ddavids  | [email protected] | 12345678
(1 row)

node-sequelize-examples=# select * from "location";
 id | locationName
----+--------------
  1 | floor
  2 | shelf
(2 rows)

node-sequelize-examples=# select * from "item";
 id | itemName  | orderDate  | userId | locationId
----+-----------+------------+--------+------------
  1 | Good Book | 2020-01-20 |      1 |          1
  2 | Bad Book  | 2020-01-21 |      1 |          2
(2 rows)

Data records inserted as expected.

sequelize version: "sequelize": "^5.21.3",

Source code: https://github.com/mrdulin/node-sequelize-examples/tree/master/src/examples/stackoverflow/59937776

like image 160
slideshowp2 Avatar answered Nov 01 '22 15:11

slideshowp2