Как добавить динамические дополнительные атрибуты в таблицу соединений с ассоциацией ManyToMany в Sequelize - PullRequest
0 голосов
/ 07 января 2019

Я создал ассоциацию «многие ко многим» с помощью sequelize в своем приложении коа. Но я понятия не имел, как создать дополнительные атрибуты в соединительной таблице. Спасибо.

Я сослался на официальный документ по сиквелизму, но не нашел решения. Вкратце:
«В заказе может быть много предметов»
«предмет может существовать во многих заказах»
Затем я создал OrderItems в качестве таблицы соединений.
Но у меня проблема с вставкой значения в таблицу соединений

// definitions
const Item = sequelize.define('item', itemSchema);
const Order = sequelize.define('order', orderSchema);

// junction table
const OrderItems = sequelize.define('order_item', {
  item_quantity: { type: Sequelize.INTEGER } // number of a certain item in a certain order.
});

// association
Item.belongsToMany(Order, { through: OrderItems, foreignKey: 'item_id' });
Order.belongsToMany(Item, { through: OrderItems, foreignKey: 'order_id' });

// insert value
const itemVals = [{ name: 'foo', price: 6 }, { name: 'bar', price: 7 }];
const orderVals = [
  {
    date: '2019-01-06',
    items: [{ name: 'foo', item_quantity: 12 }]
  },
  {
    date: '2019-01-07',
    items: [{ name: 'foo', item_quantity: 14 }]
  }
]
items = Item.bulkCreate(itemVals)
orders = Order.bulkCreate(orderVals)

//Questions here: create entries in junction table
for (let order of orders) {
  const itemsInOrder = Item.findAll({
    where: {
      name: {
        [Op.in]: order.items.map(item => item.name)
      }
    }
  })
  order.addItems(itemsInOrder, {
    through: {
      item_quantity: 'How to solve here?'
    }
  })
}

// my current manual solution: 
// need to configure column names in junction table manually.
// Just like what we do in native SQL.
const junctionValList =[]
for (let orderVal of orderVals) {
  orderVal.id = (await Order.findOne(/* get order id */)).dataValues.id
  for (let itemVal of orderVal.items) {
    itemVal.id = (await Item.findOne(/* get item id similarly */)).dataValues.id
    const entyInJunctionTable = {
      item_id: itemVal.id,
      order_id: orderVal.id,
      item_quantity: itemVal.item_quantity
    }
    junctionValList.push(entyInJunctionTable)
  }
}
OrderItems.bulkCreate(junctionValList).then(/* */).catch(/* */)

1 Ответ

0 голосов
/ 07 января 2019

В случае, если этот скрипт предназначен для посева, вы можете сделать что-то вроде этого:

/*
  Create an array in which all promises will be stored.
  We use it like this because async/await are not allowed inside of 'for', 'map' etc.
*/
const promises = orderVals.map((orderVal) => {
  // 1. Create the order
  return Order.create({ date: orderVal.date, /* + other properties */ }).then((order) => {
    // 2. For each item mentioned in 'orderVal.items'...
    return orderVal.items.map((orderedItem) => {
      // ...get the DB instance
      return Item.findOne({ where: { name: orderedItem.name } }).then((item) => {
        // 3. Associate it with current order
        return order.addItem(item.id, { through: { item_quantity: orderedItem.item_quantity } });
      });
    });
  });
});

await Promise.all(promises);

Но это не эффективный способ сделать это в целом. Прежде всего, есть много вложенных функций. Но самая большая проблема заключается в том, что вы связываете элементы с заказами на основе их имени, и возможно, что в будущем у вас будет несколько элементов с одинаковым именем.

Вы должны попытаться использовать идентификатор предмета, так что вы будете уверены в результате, а также в том, что сценарий будет намного короче.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...