117

I'm trying to output all object list from database with sequelize as follow and want to get data are sorted out as I added id in where clause.

exports.getStaticCompanies = function () {
    return Company.findAll({
        where: {
            id: [46128, 2865, 49569,  1488,   45600,   61991,  1418,  61919,   53326,   61680]
        },
        attributes: ['id', 'logo_version', 'logo_content_type', 'name', 'updated_at']
    });
};

But the problem is after rendering, all data are sorted out as follow.

46128, 53326, 2865, 1488, 45600, 61680, 49569, 1418, ....

As I found, it's neither sorted by id nor name. Please help me how to solve it.

PPShein
  • 12,193
  • 38
  • 136
  • 207

7 Answers7

266

In sequelize you can easily add order by clauses.

exports.getStaticCompanies = function () {
    return Company.findAll({
        where: {
            id: [46128, 2865, 49569,  1488,   45600,   61991,  1418,  61919,   53326,   61680]
        }, 
        // Add order conditions here....
        order: [
            ['id', 'DESC'],
            ['name', 'ASC'],
        ],
        attributes: ['id', 'logo_version', 'logo_content_type', 'name', 'updated_at']
    });
};

See how I've added the order array of objects?

order: [
      ['COLUMN_NAME_EXAMPLE', 'ASC'], // Sorts by COLUMN_NAME_EXAMPLE in ascending order
],

Edit:

You might have to order the objects once they've been recieved inside the .then() promise. Checkout this question about ordering an array of objects based on a custom order:

How do I sort an array of objects based on the ordering of another array?

Community
  • 1
  • 1
James111
  • 14,108
  • 14
  • 74
  • 116
  • I want to order like that by `46128, 2865, 49569, 1488, 45600, 61991, 1418, 61919, 53326, 61680`. – PPShein Mar 28 '16 at 10:26
  • Hmmm. You won't be able to do that (as far as I know)! You'll have to look into sorting the objects once you've received them in the .then() promise? Why do you need to order them in this specific range?! Is there a order clause that could maybe do it for you? @ppshein – James111 Mar 28 '16 at 10:28
  • I tried to do the same with a table associated with another, It did not worked. How can we do this with association @james111 – Siddhesh Khadapkar Oct 09 '21 at 12:56
6

If you want to sort data either in Ascending or Descending order based on particular column, using sequlize js, use the order method of sequlize as follows

// Will order the specified column by descending order
order: sequelize.literal('column_name order')
e.g. order: sequelize.literal('timestamp DESC')
sanastasiadis
  • 1,164
  • 1
  • 15
  • 23
meenal
  • 174
  • 1
  • 2
5

You can accomplish this in a very back-handed way with the following code:

exports.getStaticCompanies = function () {
    var ids = [46128, 2865, 49569, 1488, 45600, 61991, 1418, 61919, 53326, 61680]
    return Company.findAll({
        where: {
            id: ids
        },
        attributes: ['id', 'logo_version', 'logo_content_type', 'name', 'updated_at'],
        order: sequelize.literal('(' + ids.map(function(id) {
            return '"Company"."id" = \'' + id + '\'');
        }).join(', ') + ') DESC')
    });
};

This is somewhat limited because it's got very bad performance characteristics past a few dozen records, but it's acceptable at the scale you're using.

This will produce a SQL query that looks something like this:

[...] ORDER BY ("Company"."id"='46128', "Company"."id"='2865', "Company"."id"='49569', [...])
drs
  • 321
  • 3
  • 10
4

If you are using MySQL, you can use order by FIELD(id, ...) approach:

Company.findAll({
    where: {id : {$in : companyIds}},
    order: sequelize.literal("FIELD(company.id,"+companyIds.join(',')+")")
})

Keep in mind, it might be slow. But should be faster, than manual sorting with JS.

2

May be a little late but want to mention an approach.
Sorting based on the [46128, 2865, 49569, 1488, 45600, 61991, 1418, 61919, 53326, 61680] can be done using ARRAY_POSITION function of postgreSQL.

const arr = [46128, 2865, 49569,  1488,   45600,   61991,  1418,  61919,   53326,   61680];
const ord = [sequelize.literal(`ARRAY_POSITION(ARRAY[${arr}]::integer[], "id")`)];

return Company.findAll({
    where: {
        id: arr
    },
    attributes: ['id', 'logo_version', 'logo_content_type', 'name', 'updated_at'],
    order: ord,
});
Agniveer
  • 330
  • 1
  • 16
0

I don't think this is possible in Sequelize's order clause, because as far as I can tell, those clauses are meant to be binary operations applicable to every element in your list. (This makes sense, too, as it's generally how sorting a list works.)

So, an order clause can do something like order a list by recursing over it asking "which of these 2 elements is older?" Whereas your ordering is not reducible to a binary operation (compare_bigger(1,2) => 2) but is just an arbitrary sequence (2,4,11,2,9,0).

When I hit this issue with findAll, here was my solution (sub in your returned results for numbers):

var numbers = [2, 20, 23, 9, 53];
var orderIWant = [2, 23, 20, 53, 9];
orderIWant.map(x => { return numbers.find(y => { return y === x })});

Which returns [2, 23, 20, 53, 9]. I don't think there's a better tradeoff we can make. You could iterate in place over your ordered ids with findOne, but then you're doing n queries when 1 will do.

Alex Moore-Niemi
  • 2,285
  • 2
  • 22
  • 21
0

if required, databases order their output by the generic order of values in the order by fields.

if your order is not like this, you may add to the select an order_field, and give it a value based upon the value in id:

case 
when id=46128 then 0
when id=2865 then 1
when id=49569 then 2
end as order_field

and order by order_field.

if there are lots of values, you may stuff them in their original order in a temporary table with an identity primary key order_field, and inner join your select to that temporary table by your value field, ordering by order_field.

i don't know how to do this in sequelize, but found here answers on how it does things that i needed.

alex
  • 413
  • 5
  • 9