user830186
user830186

Reputation:

Ordering for a todo list with MongoDB

I'm attempting to create my own todo list using Javascript, Python and MongoDB. I'm getting stuck on how to handle the task ordering.

My current idea is to have an order field in each task document and when the order changes on the client I would grab the task list from the db and reorder each task individually/sequentially. This seems awkward because large todo lists would mean large amount of queries. Is there a way to update a field in multiple documents sequentially?

I'm also looking for advice as to whether this is the best way to do this. I want to be able to maintain the todo list order but maybe I'm going about it the wrong way.

{
  "_id" : ObjectId("50a658f2cace55034c68ce95"),
  "order" : 1,
  "title" : "task1",
  "complete" : 0
}

{
  "_id" : ObjectId("50a658fecace55034c68ce96"),
  "order" : 2,
  "title" : "task2",
  "complete" : 1
}

{
  "_id" : ObjectId("50a65907cace55034c68ce97"),
  "order" : 3,
  "title" : "task3",
  "complete" : 1
}

{
  "_id" : ObjectId("50a65911cace55034c68ce98"),
  "order" : 4,
  "title" : "task4",
  "complete" : 0
}

{
  "_id" : ObjectId("50a65919cace55034c68ce99"),
  "order" : 5,
  "title" : "task5",
  "complete" : 0
}

Upvotes: 5

Views: 2465

Answers (4)

glued
glued

Reputation: 2639

if you're using native promises (es6) in mongoose mongoose.Promise = global.Promise you can do the following to batch:

function batchUpdate(res, req, next){
  let ids = req.body.ids
  let items = []
  for(let i = 0; i < ids.length; i++)
    items.push(db.collection.findOneAndUpdate({ _id:ids[i] }, { $set: { order:i } }))

  Promise.all(items)
    .then(() => res.status(200).send())
    .catch(next)
}

Upvotes: 0

scottgwald
scottgwald

Reputation: 609

I'm doing something similar. I added a field ind to my list items. Here's how I move a list item to a new location:

moveItem: function (sourceIndex, targetIndex) {
    var id = Items.findOne({ind:sourceIndex})._id;
    var movinUp = targetIndex > sourceIndex;
    shift = movinUp ? -1 : 1;
    lowerIndex = Math.min(sourceIndex, targetIndex);
    lowerIndex += movinUp ? 1 : 0;
    upperIndex = Math.max(sourceIndex, targetIndex);
    upperIndex -= movinUp ? 0 : 1;
    console.log("Shifting items from "+lowerIndex+" to "+upperIndex+" by "+shift+".");
    Items.update({ind: {$gte: lowerIndex,$lte: upperIndex}}, {$inc: {ind:shift}},{multi:true});
    Items.update(id, {$set: {ind:targetIndex}});
}

Upvotes: 0

snez
snez

Reputation: 2480

Mongo is very very fast with queries, you should not be as concerned with performance as if you were using a full featured relational database. If you want to be prudent, just create a todo list of 1k items and try it out, it should be pretty instant.

for (var i = 0; i < orderedListOfIds.length; i++)
{
  db.collection.update({ '_id': orderedListOfIds[i] }, { $set: { order:i } })
}

then

db.collection.find( { } ).sort( { order: 1 } )

Upvotes: 2

georg
georg

Reputation: 215029

Yes, mongo allows for updating multiple documents. Just use a modifier operation and multi=True. For example, this increments order by one for all documents with order greater than five:

todos.update({'order':{'$gt':5}}, {'$inc':{'order':1}}, multi=True)

As to the best way, usually it's better to use a "natural" ordering (by name, date, priority etc) rather than create a fake field just for that.

Upvotes: 0

Related Questions