Save relation items order (Issue #2166)

@tsvecak it’s not a simple thing to implement from a developers view, non-technical users see it as something simple to implement but there is a massive overhead (and grows quickly as the number of related entries also increase).

It’s also extremely rare for most API-based application to allow for a manual ordering like that typically you would just sort on an existing field (usually an ID or a date/time). While we won’t allow for manual ordering in v4 we will offer the ability to sort relations by specific fields.

A simple implementation may be adding a "position" field (or "strapi_position") under the hood for each ContentType entry. And have a drag and reorder functionality for the entries implemented into the UI View below such that when a reorder occurs, the "position" field of the entries under the hood changes to reflect the new order and it syncs with the server database. This new order becomes the default order that strapi feeds out for a standard API call or (for backwards compatibility) the new ordering can be gotten with something like "...contentType/?_sort=position:ASC".

On whether this is a necessary feature, I think it’s a big plus. The order strapi feeds out entries of a contentType is in most cases the same order it is naturally implemented in the UI by a developer. I have to say the current order it feeds out entries in it’s api responses is plain bad. Today, I had to enforce add a ?_sort=id:DESC on all api requests for a particular project. I had just uploaded new book entries for the project and on the UI expected the new books to show on top of the list but strapi consistently sent old entries as the first 2 entries in the api calls. Imagine pushing a new commit to github and in the commit history UI you see a commit from 2 years ago at the very top. WHAT THE …!! That’s very unnatural. I don’t even understand the order behaviour as it’s not predictable or consistent.

While ordering based on time/order of upload can be enforced with ?_sort=id:DESC as I said earlier, for some use cases like deciding priority for different entries (on the UI view at least, higher up or bottom down), having this is a big blessing. Plus there’s simply no maintainable way to implement this at scale for a high volume of entries. Implementing this is very consitent with the simplicity of strapi which is why I personally love it (and I believe you’ll agree too).

Please consider it. Thanks.

2 Likes

I understand it’s not that easy, but we’ve seen community propose solutions one of which actually does the job(Save relation items order (Issue #2166) - #6 by roelbeerens - clear all the rows and re-save them after the post is saved).
Granted it’s a hacky way of doing things but still better than not having an option at all.

After all this is a CMS that we’d like to give our customers to work with and not developers to manage.
Only other solution is to get even more hacky with custom field that holds the order or something else that I can order the list by.

No customer out there will be happy with the fact that they can’t do a simple action of changing the order of items. Wordpress has this for a long time and all other CMS have it as well.

While Strapi is API based and they usually don’t allow manual ordering, strapi advertises itself as a leading open-source headless CMS and this is a basic CMS functionality.

For now I can live with a hack solution that was suggested above but can’t see any larger customer being happy with me handing them CMS without these basic functionalities.

1 Like

I’m curious to know what other CMSes you’ve noticed this on as we regularly check numerous other CMSes and have noticed that missing feature as well. The primary reason for not having it is a technical and performance challenge on how to properly manage it without causing major performance problems especially in larger applications.

Wordpress has this feature, I dont want to start complaining about something that im using for free but if you want this to get adopted then i am not understanding why the focus seems to be on ‘nice to have’ features instead of absolute essentials like this.

How can you expect a user to manage and order possibly thousands of posts by manually setting an ‘order’ property?

You should at minimum remove the drag and drop interface because people will assume its there to order things and not for no reason at all.

I mean simplest example is wordpress. Granted it’s through usage of Advanced Fields but I doubt there’s many wordpress’s out there without advanced fields that do some interesting things. Aside from advanced fields plugin itself, there are other plugins that are pretty much standard in wordpress for re-ordering posts, custom fields etc.

I can see how this can temper with the performance in large applications(talking about thousands items) but I am sure you can see the big issue in having to edit 100s of entries to change the order of items regardless of which approach you take to tackle this.
Otherwise how can our customers manage the order themselves that is not dependant on date or some value? Is there a better alternative?

Reason why I am also surprised this is not considered a bit more is especially as UI offers drag and drop and actually saves that order that you’ve created in the UI. Could we somehow gain access to that saved order list?

As dtah mentioned above I don’t like complaining about free stuff either but I am pretty sure most of the community would be ready to pay for strapi as well since it provides a lot of benefits, however these benefits are now solely focused on developers rather than final consumers(customers using CMS).

We are already planning to remove that, it was never intended to be on that particular interface and is used elsewhere but accidentally got injected there too.

Since we are not a monolithic CMS but instead a headless one, typically you wouldn’t and instead you would sort during the API request time based on the order you need (created/updated/published datetime or some other field).

I’ve never seen a REST or GraphQL API interface that generally allows you to manually order something though I understand your point.

And it’s for this exact reason why even injecting automation is extremely damaging to performance, you have to look at this from the technical complexity required to handle something like this at the most base level => the database.

Take for example you have an entry with say 100 relations, then 200, maybe 1000 and you want to manually order those through the interface.

In SQL (I’m throwing out NoSQL since we are dropping support for it with v4) keep in mind you cannot reorder the entries in the database, SQL databases organize entries to the table based on the time they were added and are assigned a auto-increment ID. You can’t fundamentally swap IDs of entries (you can but it’s not a fun process, and one you certainly won’t be automating) nor should you since it’s designed to be the unique ID for that entry. Meaning you now need to add an integer field or something like it to keep track of the order, we already do this with components since you can manually order those.

Now say in the 1,000 relation entry you want to move item 874 to position 4, that’s 870 entries that have to have their order adjusted and it needs to happen fast. That is one very massive bulk update, especially if you aren’t scaling the backend (horizontally or vertically). Since node is single threaded and you most likely can’t do that big of a query in one go (there are limits to the size of a SQL update query you can make, default on MySQL for example is 1 Mib, you can confirm your maximum with SHOW VARIABLES LIKE 'max_allowed_packet';).

TLDR: It’s easier said then done to actually implement something like this, and the question becomes is it really worth it or is it just a matter of designing a content structure that doesn’t rely on manual ordering?

For now you are completely correct, our current focus is on developers. Given we will expand into content creators/managers, ect later on; our core focus right now is still developers.

FYI, I’m not saying this wouldn’t be a good feature to add, I am only looking at this from the perspective of a previous community member (I’ve been around since early 2017 and only joined the Strapi team in an official capacity just over a year ago).

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. I also use Strapi myself on various personal projects one of which being a 3rd party API for a video game called Elite Dangerous:

And at the same time it’s powering various tooling that I’ve built or other tools in the ED community:

In most, if not all, of these examples time based results are the most common or if it’s time based then there are custom filters, sorting, paging, ect depending on the requirement.

1 Like

I have to say, this is tough to hear and really makes me regret choosing Strapi as a CMS. I’ve increasingly been thinking I made a real mistake in looking at this as something that could support even a standard agency website with a small editorial team managing it, and this comment confirms it.

For what it’s worth (and this is just my opinion) a CMS has to be a tool for content creators first. My clients and stakeholders really aren’t invested in what the developer experience is like, they want something that is going to give them the superpower of managing their site in an intuitive way with little outside assistance.

Now that I know the editorial experience isn’t a priority for the team, I’m in the position of having to explain this to my stakeholders and decide whether it’s worth it to continue building with this tool, or to cut my losses and rebuild with something tried and true — a very unfortunate scenario.

1 Like

Keep in mind we aren’t “just a CMS” but Strapi is a Headless CMS, the intention has always been that some developer experience is required and expected. We are moving more towards that Content manager/editor experience but we need to make sure we get all of the kinks worked out for the developers so they can help build the plugins that everyone needs to have a fantastic experience.

Our focus since June 2021 right now is entirely rebuilding large parts of the project with our v4 (see: Strapi v4 stable is live) which includes an entirely new design system, plugin API, and completely rewriting the backend Database/Query layer from scratch. Our hands are a little full at the moment with such a small team :wink:

As with everything, it takes time. The next 2 big features on our map certain are more geared towards content managers/editors (content versioning and publication workflows) and I would advise you vote for or submit feature requests on https://portal.productboard.com/strapi/1-roadmap/tabs/2-under-consideration as we base a lot our decisions on the data we get there.

I’d like to push back on this and say that almost every website I’ve made that has a marketing strategy attached to it leverages features like this. Here’s a use case I’m trying to accommodate as we speak:

I have a website with a series of case studies outlining the different types of projects a company has worked on over the years. On the homepage, there’s a section where a subset of those case studies are “featured” in a carousel/slider.

These features are changed up every once in a while:

  • when projects are updated and they want to promote the changes
  • when the marketing team decides they want to highlight certain types of projects for a period of time
  • when new things launch

The order matters to the marketing team, because part of their strategy involves controlling the visibility of these things.

Maybe this isn’t what Strapi was meant to be used for, but that’s not the impression I got when doing a surface-level analysis of it (which is admittedly on me).

2 Likes

This can easily be solved by adding 2 date fields for start_promo_date and an end_promo_date then simply having the frontend filter it’s current date to fetch those promo projects.

Or alternatively you can simply add a boolean to set promo status and then use a sort parameter during the request to get those projects first (or in combo with the dates)

There are various ways to handle it currently that aren’t intrusive to a content manager, we ourselves do the same thing on the https://strapi.io website. Especially with: Blog Strapi | Open-source Node.js headless CMS (and all it’s various tabs and the content loaded on them).

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