Save relation items order (Issue #2166)

It’s just a matter of building a content model structure that fits what you want to do in the frontend without adding too much complexity that makes a content managers job harder or too complex to easily understand.

Honestly on 2nd thought, a single date field would work perfectly and you could even schedule the promo project swap out wayyyy in advanced and simply filter out dates higher than the current and then sort by that date.

Doing so would be crazy easy and even provide the benefit of being able to make changes in advance and your frontend could automatically update on a schedule.

(I only thought of this, as I was looking at the Strapi project that runs our website, and it’s literally exactly what we do with blog posts :laughing: )

Yeah, I get what you’re saying (and appreciate the tips).

There are places that we do similar things on the site, but let’s say I’ve got a well of 40 projects to choose from, and I want to highlight 4 of them by setting the same start_promo_date and end_promo_date values for each. In that case I’d need another field (something like a weight or order field) if I also wanted to control the order that they appear in arbitrarily.

If that’s right, it just seems like a more cumbersome ask for a content editor (open each project entry individually, pick the dates you want, and then add an order number to them, and remember to change all those things when you update new promos) vs just having a draggable list with a nice typeahead interface on the homepage model.

That’s why I suggested the other option, you simply have 1 date instead and use that to control what is a promo and when; and you can use it to determine the weight.

The query would just be something like (using pseudo code as its almost the end of the day on a friday):

  • only select entries less than or equal to today (based on that single date field)
  • order by the single date field (could be asc or desc, doesn’t matter)
  • set a limit for 3, 5, or however many your front end shows
  • ???
  • profit

you wouldn’t need to worry about older promos if you have some kind of schedule going on, so no need to “clean up” the older entries and boom easily ordering and can even schedule stuff way in advanced.


If you had some massive list and you need to push those specifically to the top it’s just a matter of making two calls in the frontend to build the list. First one is the special projects, then the rest and run a simple promoList.concat(everythingList) to combine the two arrays into one and load the interface. So long as you use the promo list as the primary array and concat the rest onto it then boom. You have an ordered promo list and then everything else (could be sorted by created/updated in desc or whatever).

Date sorting is pretty powerful and honestly how most of the web functions.

Would a ‘reorder items’ button that links to a new page help with]

Thanks for explaining why this would have performance issues. Could the items of 1000 be split into groups where only the items in the groups changed would need to be affected instead of every single one that comes after it?

Why should this possible performance issue take precedence over the issue of not being able to order your items though?

If the app doesn’t do it then it means that the person (this is a developer problem too, Not just content uploader’s) will have to do it. Can you imagine how you would even do this yourself? You couldn’t.

There is no way you could manually reorder possibly thousands of posts by a order property however a computer could do this quite easily.

I hope you can appreciate that many developers will be kicking themselves about choosing strapi to build out someones website, Telling a client they will have to do this because ‘we don’t want to send too many write requests to the database’. I don’t think any of us are ignoring the fact there will be some performance issues but that would be a nicer problem to have instead of just not implementing it.

You realise that everyone that would be facing these performance issues are the people with issues such as ‘I will have to manually keep track of and update 2000 blog posts because I need this item to come first’

I think those people will choose some performance issues and delayed updating of the database or pretty much any poor solution compared to no solution at all.

I also think you should put a warning on your documentation site about these issues that strapi has without any plan to fix so that developers can make a good judgement about whether to choose strapi or not, That would be developer friendly.

Since I just ran into this issue, here’s a very simple, not super efficient but working for the moment solution… It’s for tags, but should work for all kinds of relations. It’s of course not great that every row gets re-inserted - one could write some logic to only write rows that don’t exist yet. But hey, on a small site, let’s just keep it simple…

this is just using the lifecyle function beforeUpdate to wipe the relations and re-write them in the new order, before updating the rest of the document.

module.exports = {
  lifecycles: {
    async beforeUpdate(params, data) {
      if (params.id) {
        if (data.tags) {
          await strapi.connections.default.raw(
            `DELETE FROM projects_tags__tags_projects WHERE project_id=${params.id};`
          );
          for (const tag of data.tags) {
            await strapi.connections.default.raw(
              `INSERT INTO projects_tags__tags_projects (project_id, tag_id) VALUES (${params.id}, ${tag});`
            );
          }
        }
      }
    },
  },
};

i’m against deactivating the functionality to reorder.

  1. The workarounds mentioned here are working. they might be not nice, but easy to implement and working.
  2. you have all hands on deck for V4, thus no need to put time into V3
  3. Removing it would break apps which already make use of this functionality today(e.g. by using the workarounds from here)
5 Likes

Has Anyone found any solution for this ? So that relation order remains the same as selected

When I save the relation in a particular order it remains same in sqlite but returns to original order in Postgresql. Anyone knows this issue?

Hello.

I’ve also encountered this problem when using PostgreSQL - above fix with re-deleting relations would not retain order in which they were created. As this feature is important for our project, I’ve taken a look in the underlying ‘strapi-connector-bookshelf’ library and fix the issue there.

This fix will order relations based on the ‘id’ (basically in the order they were created), as I didn’t want to create another field (like ‘order’), which content creators would have to manage. Also, this fix may break when new Strapi updates roll in, so use it on your own risk.

  1. Install a forked strapi-connector-bookshelf using npm install good-vision-slovakia/strapi-connector-bookshelf#master. This package contains a fix to retain order of “many” relations when selecting or updating an entity.
  2. Go to your content type’s model folder and open the "<content_type>.settings.json". Inside, you will find your relation attribute under “attributes” key - insert a new key with value “withPivot” set to “[“id”]”. All of this could look like:
{
  "kind": "singleType",
  "collectionName": "collection",
  "info": {
   ...
  },
  "options": {
   ...
  },
  "pluginOptions": {
    ...
  },
  "attributes": {
    ...
    "<many to many related collection>": {
      "unique": true,
      "collection": "categories",
      "withPivot": ["id"] // Insert it here
    }
  }
}
  1. You will have to delete the collection’s relation items in the model’s beforeUpdate lifecycle. This will ensure the creation in the order they were specified. This could look like:
module.exports = {
  lifecycles: {
    beforeUpdate: async (params, data) => {
      // Enforce the order in which headline categories are displayed.
      // This will delete data before update, but they will be re-inserted by Strapi.
      // Order is determined by the id.
      await strapi.connections.default.raw(`
        DELETE FROM <your table>;
      `);
    },
  }
};

All of this worked for me and I can finally be “productive” with other things. I just hope this issue will get fixed in v4.

Just here to find out the current status the conversation on this. There is an issue open on the github kanban board, but that is only linked to a closed PR that is for v3.

Sorted relationships are table stakes/must haves for many applications, as seen in this thread and in the related github topic for sortable collections. Ordering Content Type entries in the List view (preferably using drag and drop) · Issue #3946 · strapi/strapi · GitHub

Most of the assumptions made in this thread are spurious and mis-informed. What REST APIs allow content to be manually sorted? Playlists for one. (Youtube, Spotify) How do you update hundreds of rows in order “to move item 874 to position 4, that’s 870 entries that have to have their order adjusted and it needs to happen fast.”

UPDATE table set sort_order = sort_order + 1 where sort_order >=4 and sort_order<875;
UPDATE table set sort_order = 4 where id = <moved_item_id>;

I haven’t looked at how this works under the hood in SQL, but typically this is done with a new table in between. Playlists → Playlist_songs → Songs.
At Spotify I don’t want any users to edit song content, but I want users to add the link to the song to their playlist and reorder.

This is just so so basic. It’s sad to see that the product team has not considered this even as the product reaches v4.

It doesn’t seem as if Bookshelf.js prioritizes or includes/allows for any metadata around the relationship.
Here is a description of how Django handles it.
https://docs.djangoproject.com/en/4.0/topics/db/models/#extra-fields-on-many-to-many-relationships

I was pretty surprised to find this feature lacking in Strapi! I was looking for exactly what @JohnRomanski suggested, adding fields to the relationship ‘join table’. This is the common way to handle this in SQL, and has been supported by some CMS’s for many years… I remember first encountering it in SilverStripe over a decade ago.

@jorisw that worked great! Do you know if it’s possible to update the component through a REST API PUT request? Or only through the admin view?

No idea. I would expect so. Surely one of the Strapi people in this thread could tell you?

In the 4 years that I’ve been around Strapi and all of the other platforms I’ve looked at (Wordpress included) I have never seen a viable reason to manually order content.

Then you haven’t been around enough. We have this exact need. We do e-learning courses and digital textbooks. This is a very common requirement for linear course-type content applications.

For the courses, there are multiple lessons that are being maintained. Many of the lessons are reused in other courses (many-to-many), so a simple field with “lesson order” doesn’t work, because a lesson might be ordered in a specific position for one course and be ordered in a completely different position in another course. Plus, some courses have over a hundred lessons. Imagine having to re-order all of those manually when you want to add a new lesson in between two others, or simply re-order them. As we continually update course versions, this is done daily.

Furthermore, each lesson has multiple “slides.” Same issue with these.

And where Strapi really breaks down for us is using it for linear, digital textbook content. We have units, sections, chapters, and pages; and are continually adding and re-ordering them. Some books have hundreds of pages of content.

Strapi simply doesn’t have the functionality we need for the content structure we require and is not useful for e-learning applications that require linear course-type content structures. We’d have to build an intermediary application to handle this and that would introduce a whole new set of challenges, but thankfully other platforms support this. So we are using one of their competitors. Our developers preferred Strapi during the evaluation process, but the lack of ability for our teachers to easily re-order collections of content related to others was a deal killer for us.

2 Likes

We power an ecommerce site where we have the same need for different orders in different collections. We were really hoping strapi v4 will sort this as promised but it seems like it didn’t. Which competitor did you go for?

Anyone here found a solution?

Recently I came through this issue and decided to create a repeatable component that contains only one relation to the collection.

The list of repeat table is stored in orders so we have extra fields in the API response but instead we can have an ordered list of relations ( data inside the collection type can be populated successfully using populate query )

Just my little help!

Unfortunately no. I just assumed this would be in there since every CMS has it in either their core or via a plugin everyone installs. Wordpress/ExpressionEngine/Craft/Drupal - you name it.

I read a note from earlier from the Strapi team where they said that this likely won’t be a feature anytime soon. I hope I’m wrong. The quote was that they’re focused on developers and not content creators which just doesn’t work for real world scenarios. A CMS in the end is for content creators/marketing directors/etc, not developers. It’s why CMS’s exist. Changing the order of products on the homepage should not require a client to call us. That’s the CMS’s job. Will check back on Strapi from time to time as it’s maturing, but this is just a non-starter for us.

1 Like

Apologize in advance if my note came off as snarky. I only cared to write that note because I see the potential of Strapi. I have yet to find a good, solid, polished Node based CMS out there and I think Strapi is right on the cusp of gaining a mass market following. Just need to get these little things right and we’d be moving over to it full time.

Great job to the devs on v4. Just need these little polishes before we jump off the PHP ship. And trust us - we want to jump off the PHP ship.