简体   繁体   中英

Sequelize Op.notIn with Sequelize Model

Hello i have a mysql query which is working fine in sequelize.query and the query is

 select list_name from lists l where l.list_id not in (SELECT sub.list_id from list_sub_activities sub left join. Activities a on a.list_act_id = sub.list_act_id where a.agency_id = 2)

and i want to do the same using the sequelize model, i have tried but i think i am missing something.

List of Package ---> lists

 List_of_Packages.findAll({ attributes: ['list_name'], where: { list_id: { [Op.notIn]: [List_sub_Activities.findAll({ attributes: ['list_id'], include: { model: Activities, required: false, where: { agency_id: 2 } } }) ] } } }).then((response) => { console.log(response); })

I appreciate that if you help me.

Thank you !!!

The findAll() (and other query methods) are asynchronous so you will need to resolve the promise (or use a callback) to resolve the value before you can pass the list_id s to Op.notIn . It will also return an array of objects with a property of list_id , so you will need to map this to an array of integers before you can use it. You can also pass in raw: true so that it will not generate Sequelize Instances from your results and will instead return plain javascript objects - this is more efficient than creating objects just to fetch a single property.

By setting required: false on the Activities include you will be returning all List_sub_Activities and not filtering on them (some will be null in your results). This is likely not what you intended.

This example uses async/await for clarity instead of thenables . Note that this is not the most efficient as it requires multiple database queries, the ideal solution would be to use a LEFT JOIN and then remove items where the package.list_id IS NULL (see second example).


// get an array of Activities with the list_id set
const activities = await List_sub_Activities.findAll({
  attributes: ['list_id'],
  include: {
    model: Activities,
    // don't use required: false to only return results where List_sub_Activities.Activities is not null
    // required: false,
    where: {
      agency_id: 2,
    },
  },
  raw: true,
});

// map the property to an array of just the IDs
const activityIds = activities.map((activity) => activity.list_id);

// now you can pass the activityIds to Op.notIn
const packages = await List_of_Packages.findAll({
  attributes: ['list_name'],
  where: {
    list_id: {
      [Op.notIn]: activityIds,
    },
  },
});

With thenables.

List_sub_Activities.findAll(...)
.then((activities) => activities.map((activity) => activity.list_id))
.then((activityIds) => List_of_Packages.findAll(...))
.then((packages) => {
  console.log(packages);
});

This example LEFT JOINs List_of_Packages to List_sub_Activities which is JOINed to Activities with a WHERE setting the agency_id to 2, then only returns results from List_of_Packages where the List_sub_Activities.list_id is NULL (nothing was matched on the LEFT JOIN). This should return the same results as above in a single query.

// Get List_of_Packages where there is no match in List_sub_Activities after 
// it is joined to Activities with the agency_id set.
const agencyId = 2;
const packages = await List_of_Packages.findAll({
  attributes: ['list_name'],
  include: {
    model: List_sub_Activities,
    // we don't need to actually fetch the list_id
    attributes: [],
    include: {
      model: Activities,
      where: {
        agency_id: agencyId,
      },
    },
    // uses a LEFT JOIN
    required: false,
  },
  // only return results where the List_sub_Activities.list_id is null
  where: sequelize.where(sequelize.col('List_sub_Activities.list_id'), 'IS', null),
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM