Database / collection of an arbitrary but specific order

I want to create a database (I use mongodb) that has a specific order, which can also be rebuilt. For example, if I have

[A,B,C,D,E]

I could move E to third position, and the order would be

[A,B,E,C,D]

I would like to change as few objects as possible, so setting an index on each object will not work (since I will need to change the indices of all subsequent elements for a simple move).

I could also create objects as a linked list, so each object would have the identifier of the previous and next objects. An example of a change would be as follows.

["A":{prev:null, next:"B"},
"B":{prev:"A", next:"C"},
"C":{prev:"B", next:"D"},
"D":{prev:"C", next:"E"},
"E":{prev:"D", next:null}]

change to

["A":{prev:null, next:"B"},
"B":{prev:"A", next:"E"},
"C":{prev:"E", next:"D"},
"D":{prev:"C", next:null},
"E":{prev:"B", next:"C"}]

5 . , , , . , , , . ?

+5
1

, , , 500 7 "" ( - ). , , "" / . , , O (n). 0,8 , , , O (1).

, / :

var populateMulti = function(colSize) {
   db.test10.drop();
   for(var i=0;i<colSize;i++) {
      db.test10.save({name:""+i, order:i});
   }  
   db.test10.ensureIndex({order:1});
}

var populateLinked = function(colSize) {
   db.test10.drop();
   db.test10.save({name: ""+0, prev:null, next:""+1});
   for(var i=1;i<colSize-1;i++) {
      db.test10.save({name:""+i, prev:""+(i-1), next:""+(i+1)});
   }  
   db.test10.save({name: ""+(colSize-1), prev:""+(i-1), next:null});
   db.test10.ensureIndex({name:1});
}

. 5 - , .

var moveMulti = function(oldPos,newPos) {
   if(oldPos == newPos) return;
   db.test10.update({order:oldPos}, 
                    {$set:{order:newPos, hold:true}}, 
                    false, false);
   if(oldPos < newPos) {
      db.test10.update({order:{$gt:oldPos, $lte:newPos}, hold:{$exists:false}},
                       {$inc:{order:-1}}, 
                       false, true);
   } else if(newPos < oldPos) {
      db.test10.update({order:{$gte:newPos, $lt:oldPos}, hold:{$exists:false}},
                       {$inc:{order:1}}, 
                       false, true);
   }
   db.test10.update({order:newPos}, 
                    {$unset:{hold:1}}, 
                    false, false);
}

var moveLinked = function(oldPos,newPos) {
   var toMove = db.test10.findOne({name:""+oldPos});
   var dest = db.test10.findOne({name:""+newPos});
   if(toMove.prev != null) {
      db.test10.update({name: toMove.prev}, {$set:{next:toMove.next}}, false, false);
   }
   if(toMove.next != null) {
      db.test10.update({name: toMove.next}, {$set:{prev:toMove.prev}}, false, false);
   }
   if(dest.prev != null) {
      db.test10.update({name: dest.prev}, {$set:{next:toMove.name}}, false, false);
   }
   db.test10.update({name: toMove.name}, {$set:{prev:dest.prev, next:dest.name}}, false, false);
   db.test10.update({name: dest.name}, {$set:{prev:toMove.name}}, false, false);
}

. , : https://gist.github.com/1700270

:

coll size: 10; finished 5000 moves with multi-update in: 1188ms; 0.2376ms per move
coll size: 10; finished 5000 moves with linked in: 3593ms; 0.7186ms per move
coll size: 100; finished 5000 moves with multi-update in: 7545ms; 1.509ms per move
coll size: 100; finished 5000 moves with linked in: 3800ms; 0.76ms per move
coll size: 500; finished 5000 moves with multi-update in: 37754ms; 7.5508ms per move
coll size: 500; finished 5000 moves with linked in: 4027ms; 0.8054ms per move
coll size: 1000; finished 5000 moves with multi-update in: 71609ms; 14.3218ms per move
coll size: 1000; finished 5000 moves with linked in: 4221ms; 0.8442ms per move
coll size: 10000; finished 5000 moves with multi-update in: 676043ms; 135.2086ms per move
coll size: 10000; finished 5000 moves with linked in: 4041ms; 0.8082ms per move
+2

All Articles