简体   繁体   中英

Sorting MongoDB documents with the same update-timestamps?

I want to test a route in my Express server with Supertest . On that route i will get a list of data from the MongoDB and that data is sorted by the updatedAt field .

I wan to test if the order in the output is the right way, but I have a problem - it seems that mongoDb is so fast that some of the documents have the same timestamp (didn't think that was possible).

在此处输入图片说明

How is this sorted internally? It seems like it is not sorted by _id either. Here is the function in my test that generates the documents:

let first;
let last;
Array.from(Array(14)).forEach((e, i) => {
  const immo = new Immo({ user: this.user.model });
  immo.save();
  if (i === 2) {
    // last means last with limit 12 sorted by timestamps descending
    last = immo._id.toString();
  }
  if (i === 13) {
    // the last that was put in will be the first in the sorted list
    first = immo._id.toString();
  }
});

The output is the last 12 items that the user has edited. I save the first and the last so I can assert them later in the test.

But the test fails because there are 3 or 4 with the same timestamp and the one that is actually the last in order of how I put it in the DB is not really the last when Mongo sorts it by timestamps (or first in descending order).

I tried to make a delay via for-loop in the input-loop but that did nothing. (Should I maybe not use Array.forEach?)

Is there any way I can make sure that there is at least a few MS delay between the documents?

Turns out my problem was that I didn't consider the asynchronous nature of all the processes.

I wrapped everything in Promises and it works now. Here is my new code:

it('should return a list of the last 12 objects if a user has 14 objects', function (done) {
    let first;
    let last;
    let i = 0;
    const model = this.user.model;
    (function recur() {
      i += 1;
      return new Immo({ user: model })
        .save()
        .then((result) => {
          if (i === 3) {
            last = result._id.toString();
          } else if (i === 14) {
            first = result._id.toString();
          }
          if (i >= 14) {
            return result;
          }
          return recur();
        });
    }())
    .then(() => {
      this.request(this.app)
        .get(url)
        .set('Authorization', this.authHeader)
        .expect(200)
        .end((err, res) => {
          if (err) {
            done.fail(err.message);
          } else {
            expect(res.body.count).toBe(14);
            expect(res.body.objects.length).toBe(12);
            expect(res.body.objects[0]._id).toEqual(first);
            expect(res.body.objects[11]._id).toEqual(last);
            done();
          }
        });
    });

Not sure if this would work below ES2015 since I use the generating function recursively.

Mongoose complains when I use it's own Promises. Then I do this on top of my test-setup function:

const mongoose = require('mongoose');
mongoose.Promise = require('q').Promise;

I hope it was worth it to waste so much time on this one test :D

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM