Issues with multiple Mongo update operations

Here is the deal - I have records in a mongo collection called “pages”. Each “page” has an “order” field, which is basically an integer that is used for sorting of the records later. I have a drag & drop UI for pages reordering. On every drop, I send the new pages order as array of objects like this:

[{_id:'2', order:0},{_id:'5', order:1},{_id:'1', order:2}]

On the server I update the pages collection like this:

newOrder.forEach(function(page){
    Pages.update(page._id, { $set: {order: page.order} });
});

Then in the client I subscribe for the Pages collection and I have a getMeteorData method because I use React:

getMeteorData () {
    return {pages: Pages.find({}, {sort: {order: 1}}).fetch()}
},

This works… kinda. The problem is that the client that sends the new order doesn’t update the UI properly. It gets partial server results and partial minimongo client results at the same time, because updating happens too fast (I work on localhost and in real life it won’t be so fast, but still it is an issue).
Anyways, calling Pages.update for every single page is far from optimal, I know. And this brings the problem with partial updates too. Any idea how could I make it better? Some way to prevent data server push until the forEach loop finishes and then push the changes at once? Or to remove the client-side minimongo storage for that particular collection and make it update only after server response? Or a better reordering storing approach? Any idea is more than welcome!

Meteor methods have this latency compensation feature built in. You need to run the Meteor method with the forEach loop also on the client (1). In the documentation the client side Method implementation is called stub: http://docs.meteor.com/#/full/meteor_methods.

(1) by putting the file in a location where it also gets shipped to the client

Hi, Sanjo. I think the latency compensation mechanism is exactly the thing that messes it up. I have the mongo updates in a method that is accessible both server and client side:

'pages.reorderPages': function (data) {
    check(data, Array);

    //if (Meteor.isServer){
        data.forEach(function(page){
           Pages.update(page._id, { $set: {order: page.order} });
        });
    //}
  }

well, the helper re-run for every update there.
maybe it would be wise to use reactive:false in helper .find and use some other reactive way of signaling when to re-run computation.

You can also store the page order as one document in a new collection. Then you can update the order of a set of pages with one update.

What do you mean by “helper”? Template helper? I don’t use Blaze. I use React. I mentioned it in the first message. Check the getMeteorData function. Do you know how can I set it reactive:false?

Sanjo, this is always a fallback option. I just don’t like this approach, especially in non-relational DBs like Mongo. There are many sync issues to deal with.

Thanks, I’ve managed to set reactive:false in Pages.find. However nothing changed. Here is what happens in the websocket:

This is the “pages.reorderPages” method call:

Here start the update responses from server:
a["{\"msg\":\"changed\",\"collection\":\"pages\",\"id\":\"gEgFrd75zLaHP8bhw\",\"fields\":{\"order\":0}}"]

a["{\"msg\":\"changed\",\"collection\":\"pages\",\"id\":\"vBDdv9X7zNiqWc8KN\",\"fields\":{\"order\":1}}"]

a["{\"msg\":\"changed\",\"collection\":\"pages\",\"id\":\"DpgGuJkgEGkivWeD3\",\"fields\":{\"order\":2}}"]

a["{\"msg\":\"changed\",\"collection\":\"pages\",\"id\":\"Zg6AMvYawnGRF5FhA\",\"fields\":{\"order\":3}}"]

a["{\"msg\":\"changed\",\"collection\":\"pages\",\"id\":\"EfrnABREvxybSM6XG\",\"fields\":{\"order\":4}}"]

a["{\"msg\":\"changed\",\"collection\":\"pages\",\"id\":\"o5mGgNiuSfjCofWcL\",\"fields\":{\"order\":5}}"]

a["{\"msg\":\"changed\",\"collection\":\"pages\",\"id\":\"N9JZ7SNy2GDRuvg5z\",\"fields\":{\"order\":6}}"]

6 of them sent, 3 are lost. Right after them, the method result is sent. I guess it has something to do with the missing 3 update messages.

a["{\"msg\":\"result\",\"id\":\"2\"}"]

Any way to suspend Meteor to publish changes until all mongo update operations finish? And then to push all the changes in one message?

1 Like

Any ideas are welcome! :frowning:

Have the same issue.

If anyone could explain how to keep sync react drag and drop/sortable libraries with meteor collections, I’ll be very glad.

For example react DND https://gaearon.github.io/react-dnd/examples-sortable-simple.html
Is there any solutions to do this without redux?