Automatically increment order numbers

And then I tried with Meteor Method, but still don’t work (base on Meteor 1.5)

import Counters from './counters';

Meteor.methods({
    getNextSequence: function (name) {
        const ret = Counters.rawCollection().findAndModify(
            {
                query: {_id: name},
                update: {$inc: {seq: 1}},
                new: true,
                upsert: true
            }
        );

        console.log(ret.seq);

        return ret.seq;
    }
});

Check my code - I used async and await.

I tried with async and await, but still don’t work

Meteor.methods({
    getNextSequence: async function (name) {
        const ret = await Counters.rawCollection().findAndModify(
            {
                query: {_id: name},
                update: {$inc: {seq: 1}},
                new: true,
                upsert: true
            }
        );

        console.log(ret.seq);

        return ret.seq;
    }
});

@orloff I had this same issue with FindAndModify is not a function. I got it working after installing meteor-find-and-modify
meteor add fongandrew:find-and-modify. Though this package isn’t actively maintained at the moment, it worked for me. It adds findAndModify support to Meteor’s MongoDB Collections. It should work on both the server and client.

@martineboh, thanks for your share.
but this package isn’t actively maintained

Yes, but works! I have had no issues using it since Meteor 4+.

Using rawCollection() gives you access to these methods, including findAndModify.

However, it turns out that findAndModify has been deprecated and a bunch of new methods has been added. So, I’ve rewritten @theara’s method to use findOneAndUpdate():

Meteor.methods({
  async getNextSequence(name) {
    const ret = await Counters.rawCollection().findOneAndUpdate(
      { _id: name },
      { $inc: { seq: 1 } },
      { upsert: true, returnOriginal: false }
    );
    return ret.value.seq;
  }
});

Hope that helps :slight_smile:

1 Like

@robfallows Thanks for the updates! Found its usage in the mongo docs

1 Like

It seems findAndModify isn’t deprecated yet according to here and here in the docs.

I really like the way you use Async/Await with Meteor Methods. Can you please rewrite the example with try/catch to show error handling…thanks :wink:

I was going by the API docs - and it’s the API which Meteor uses - so I’m playing safe :wink:.

Meteor.methods({
  async getNextSequence(name) {
    try {
      const ret = await Counters.rawCollection().findOneAndUpdate(
        { _id: name },
        { $inc: { seq: 1 } },
        { upsert: true, returnOriginal: false }
      );
      return ret.value.seq;
    } catch (error) {
      throw new Meteor.Error('ENEXTSEQ', 'Failed to get next sequence number');
    }
  }
});
2 Likes

@robfallows, thanks for your helping.
But I would like to call this in Collection Hook

Units.before.insert(function (userId, doc) {
    console.log(getNextSequence.run('unitId'));
    ........
});

dont’ work, get Promise { <pending> }

Have you tried

Units.before.insert(async function (userId, doc) {
    console.log(getNextSequence.run('unitId'));
    ........
});

still get Promise { <pending> }

Sorry, forgot that getNextSequence was an async function (btw - not sure where that .run is coming from…). Maybe something like this?

async function getNextSequence(name) {
  const ret = await Counters.rawCollection().findOneAndUpdate(
    { _id: name },
    { $inc: { seq: 1 } },
    { upsert: true, returnOriginal: false }
  );
  return ret.value.seq;
}
//...
Units.before.insert(async function (userId, doc) {
  const nextSeq = await getNextSequence('unitId');
  console.log(nextSeq);
  doc._id = nextSeq;
    ........
});

It work fine.
So it means that we must create getNextSequence as general function, if we want to use it in server (don’t Meteor Method)

You can use it in an async method if you want.

Thanks again, :+1::heart_eyes:

1 Like

Wow, have problem when I attache nextSeq with doc._id

Units.before.insert(async function (userId, doc) {
    const nextSeq = await getNextSequence.run({name: 'unitId'});
    doc._id = nextSeq;
    console.log('before', doc);
});

Units.after.insert(async function (userId, doc) {
    console.log('after', doc);
});
------------
I20170830-10:40:25.188(7)? after { name: 'Hi', category: 'Count', _id: 'PhvXJn7FBn3pesPxk' }
I20170830-10:40:25.194(7)? before { name: 'Hi', category: 'Count', _id: 5 }

Ah, yes. You can’t use numbers as MongoDB _ids - you’ll either need to force them to strings, or append them to a string:

doc._id = nextSeq.toString(); // or ...
doc._id = `${nextSeq}`; // or ...
doc._id = `abc${nextSeq}`; // etc...

It mean that inserts random id before nextSeq id return (console on before hook run after after hook).

I20170830-10:59:27.693(7)? after { name: 'Hi', category: 'Count', _id: 'roMLDXgaN6eg2ww48' }
I20170830-10:59:27.699(7)? before { name: 'Hi', category: 'Count', _id: '6' }