skip to Main Content

I made a user schema based on mongoose or mongodb, in which there is a invitation code and this code is always unique in the database.

import randomize from 'randomatic';

const userSchema = new Schema<UserDataInterface>(
  {
    username: {
      type: String,
      required: [true, "Please username is mandatory."],
      unique: false,
    },
    inviteCode: { type: String, default: randomize('0', 8)  },
    ...
  }

The invite code is 8 length long numbers generated by a randomatic library, I expect it will be different for every user, so I didn’t enforce inviteCode to be unique

but during the production, I found two latest registered users who are registered at different time have exact the same invitecode.

{
  "_id": {
    "$oid": "6656e341495d3ec1782baa7d"
  },
  "username": "ddd333",
  "inviteCode": "94770150",
  "createdAt": {
    "$date": "2024-05-29T08:11:45.240Z"
  }
}
{
  "_id": {
    "$oid": "66572d68495d3ec1782bab0f"
  },
  "username": "ddd233",
  "inviteCode": "94770150",
  "createdAt": {
     "$date": "2024-05-29T13:28:08.943Z"
  }
}

I found the problem is all user’s inviteCode is the same value,

inviteCode: { type: String, default: randomize(‘0’, 8) }.

It looks like randomize function only initalize only once

2

Answers


  1. Chosen as BEST ANSWER

    I don't know why inviteCode: { type: String, default: randomize('0', 8) } only init once for all registered users.

    so I tried

    userSchema.pre("save", async function (next) {
      this.inviteCode = randomize('0', 8);
      next();
    });
    

    and it works out.


  2. Here is an alternative that does not rely on external library but use only MongoDB aggregation operators.

    1. generate random number with $rand
    2. $multiply the number with 100000000 and $toLong to make take only integer part
    3. $toString and pad with 8 zeros in front
    4. take substring for last 8 digits
    db.collection.aggregate([
      {
        "$set": {
          // generate the inviteCode in long first; could be less than 8 digits
          "inviteCode": {
            "$toLong": {
              "$multiply": [
                {
                  "$rand": {}
                },
                100000000
              ]
            }
          }
        }
      },
      {
        "$set": {
          // convert to string and pad zeros in front
          "inviteCode": {
            "$concat": [
              "00000000",
              {
                $toString: "$inviteCode"
              }
            ]
          }
        }
      },
      {
        "$set": {
          "inviteCode": {
            // get the last 8 digits
            "$substrCP": [
              "$inviteCode",
              {
                "$subtract": [
                  {
                    "$strLenCP": "$inviteCode"
                  },
                  8
                ]
              },
              8
            ]
          }
        }
      },
      {
        "$merge": {
          "into": "collection",
          "on": "_id"
        }
      }
    ])
    

    Mongo Playground

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search