How to increment numbers Independently, in an ordering system.
Frameworks: Next.js, MongoDB, Mongoose.
Tools: VS Code, MongoDB Compass, Postman.
Lately, I was part of a project in which we created an ordering website for a local restaurant. As in all ordering sites, we needed to find a way to give a unique order-number to each order that is made using our site. A number to show to our customer. Mainly for customer support, in case they want to change or cancel the order.
You might ask: "well, why not just use the unique id generated by MongoDB?”
The answer to this is UI. We want to present our customer with a simple number, a clean number. One that is relatively easy to remember.
There is another advantage to controlling the kind of numbers, which I will expend on later.
Of course we wanted to avoid a situation in which two orders have the same order-number so we had to base our counter on the database, otherwise In each render of the site, the order-number will always go back to the initial number that was defined.
At first we used the countDocuments() of mongoose, to count the amount of the existing orders in our “orders” collection, increment it by 1, and assign this new number to the new order. This solution was fine, but it limited us because if we had to delete any orders from our collection, we might end up with two, or more, orders with the same order-number.
Eventually we created a collection with just one document that holds a number. The number in the collection is updated whenever an order is placed and the new number is assigned to the order.
We can divide the process into four Steps:
1. Defining the schemes.
2. Building and defining relevant API routes. (Post counter, Post Order)
3. Setting an initial value in the number scheme. (using ‘Post Counter’)
4. Writing two dependent functions: One function for the number and one to post the New Order with the new number.
1. Defining the schemes.
The number scheme is fairly simple, it has only one property called “number” and its value will be a Number: (lines 5-7).
The model was given the name “Counter”.
import mongoose from "mongoose";
const Schema = mongoose.Schema;
const counter = new Schema({
number: Number,
});
mongoose.models = {};
const Counter = mongoose.model("Counter", counter);
export default Counter;
The 'order' scheme is obviously a little bit more complex but we'll focus for now just on the order property of the scheme, (line 13).
import mongoose from "mongoose";
const Schema = mongoose.Schema;
const order = new Schema({
customerEmail: String,
dateAndTime: String,
specialNotesFromCustomer: String,
mealPrice: Number,
dishes: Array,
wasDelivered: Boolean,
wasCanceled: Array,
orderNum: Number,
});
mongoose.models = {};
const Order = mongoose.model("Order", order);
export default Order;
2. Building and defining relevant API routes. (Post counter, Post Order).
Now we had to create the API route to post a document to the ‘counters’ collection, in order to have an initial number which we could then further increment with each new order.
import connectDB from "../../middleware/mongodb";
import Counter from "../../models/countermodel"
const postInitialNumber = async (req, res) => {
if (req.method === "POST") {
const { number } = req.body;
if (number) {
try {
const counter = new Counter({
number
});
const counterCreated = await counter.save();
return res.status(200).send(counterCreated);
} catch (error) {
return res.status(500).send(error.message);
}
} else {
res.status(422).send("data_incomplete");
}
} else {
res.status(422).send("req_method_not_supported");
}
};
export default connectDB(postInitialNumber);
This allowed us to decide with what number to start the count. you can choose to start at zero, or 100 or whatever works best for your needs.
(In fact, you can even have more than one collection, meaning you can have more than one counting system, and you can use this to differentiate between different kinds of orders.)
3. Setting an initial value in the number scheme. (using ‘Post Counter’)
We used Postman in order to set our count to start at 10000:
Using MongoDB Compass, we monitored our result in the ‘counters’ collection:
4. Writing two dependent functions: One function for the number and one to post the New Order with the new number.
Now that we had the desired initial value in the database, we needed an API route that would increment it by one. We used the findOneAndUpdate() and the $inc methods of mongoDB to set the route.
Please note in line 7: we pass in the arguments brackets; first, empty curly brackets, followed by a nested object inside another object.
The outer object defines the method, which is incrementing. The inner object defines which property to execute the method on and by how much. In our case, we want to add 1 to the ‘number’ property.
Moreover, you can see in line 8, that we only send back the value of ‘number’ and not the whole object.
Up until now we created the schemes and models we needed, and the API routes. Now we wanted to implement all of it in the “Tray” component and connect the back-end to the front-end.
We made a “Place Order” button, and assigned it an onClick function.
<button onClick={() => newOrderNum()}> Place Order </button>
This button actually engages two functions, one after the other.
We had to set it this way because the fetch function is an async function and we need it to finish so we can have the number before posting the new order.
The first function will fetch a new order-number, and then, it will activate the second function, with the new number passing as an argument.
Notice in lines 25-27, we passed a “PATCH” method through to the API.
The information is fetched in lines 29-30. The number in the database is updated, and we receive back the number that was there before.
In line 31, we assign a variable to the number(“newOrderNum”), and in line 32 we call the second function that will post the whole order to our database.
The second function, HandleOrder, might seem more complex at first sight, but we will focus on the “order-number” element of it.
In line 37, “HandleOrder” receives the number, and in line 49 it is assigned to the “orderNum” property of the request body.
In lines 53 - 60, the request is passed through the route to the relevant API, and the whole order is posted to the database.
Again, using MongoDB Compass, we monitored our result, this time in the ‘orders’ collection:
you can see the 'orderNum' property is set to the initial value which we set at the beginning.
Furthermore, the number in the “counters” collection was incremented by 1, and is ready for the next order.
Conclusion
using a whole collection just to assign order numbers may seem wasteful. But it allows us the freedom to manage the rest of our database with more accuracy and precision. So in the long run, it will help us to be more economic in our work and thus more productive.
Thank you for reading! Hope this helps.
Available for work. Full Stack developer.
https://www.linkedin.com/in/gal-naim-גל-נעים-910460246/
Top comments (2)
Available for work. Full Stack developer.
linkedin.com/in/gal-naim-גל-נעים-9...
Great article! Simple examples and clear explanations, right to the point! Well done!