node-mongo-demo
node.js and mongodb demo
git clone https://9o.is/git/node-mongo-demo.git
commit fc2928681b8d38d0acdb2ed48c579e1fe8cb8742 parent 3382dd86e35c2c6e4fbdff09033f99e0a48d52c8 Author: Jul <jul@9o.is> Date: Mon, 27 Jan 2025 02:23:55 -0500 add GET /api/lucky7/leaderboard endpoint Diffstat:
| A | backend/infra/populate_database.js | | | 42 | ++++++++++++++++++++++++++++++++++++++++++ |
| A | backend/src/api/lucky7-leaderboard.js | | | 124 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | backend/src/api/lucky7.js | | | 2 | ++ |
3 files changed, 168 insertions(+), 0 deletions(-)
diff --git a/backend/infra/populate_database.js b/backend/infra/populate_database.js @@ -0,0 +1,42 @@ +import mongoose from "mongoose"; +import bcrypt from "bcryptjs"; +import User from "../src/models/user.js"; +import Lucky7Session from "../src/models/lucky7-session.js"; +import Lucky7Bet from "../src/models/lucky7-bet.js"; + +const startDate = new Date("2024-01-01") + +const roll = () => Math.round(Math.random()) + ? { win: true, lucky: true, roll: [3,4] } + : { win: false, lucky: true, roll: [1,1] }; + +const generateBets = (length, users) => + users.flatMap(({ _id }) => + Array.from({ length }, (_, i) => 1 + i).map(i => ({ + ...roll(), + userId: _id, + rollAt: new Date(new Date(startDate).setDate(startDate.getDate() + i)), + })) + ); + +const generateUsers = length => + Array.from({ length }, (_, i) => 1 + i) + .map(i => ({ + name: `user${i}`, + email: `user${i}@example.com`, + password: bcrypt.hashSync(`user${i}`, 12), + })); + + +(async function() { + try { + await mongoose.connect('mongodb://root:example@localhost:27017/') + await User.init(); + await Lucky7Bet.init(); + + const users = await User.insertMany(generateUsers(10)); + const bets = await Lucky7Bet.insertMany(generateBets(20, users)); + } finally { + await mongoose.disconnect(); + } +})(); diff --git a/backend/src/api/lucky7-leaderboard.js b/backend/src/api/lucky7-leaderboard.js @@ -0,0 +1,124 @@ +import Lucky7Bet from "../models/lucky7-bet.js"; + +const lucky7Leaderboard = async (req, res) => { + try { + const streaks = await getTopWinStreaks(); + res.status(200).json(streaks.map(({ streak, users }) => ({ + streak, + name: users[0].name, + }))); + } catch (error) { + console.error(error); + res.status(500).json({ message: "Something went wrong" }); + } +}; + +function getTopWinStreaks() { + return Lucky7Bet.aggregate([{ + $sort: { + userId: 1, + rollAt: -1, + } + }, + { + $group: { + _id: "$userId", + bets: { + $push: "$$ROOT" + } + } + }, + { + $project: { + result: { + $reduce: { + input: "$bets", + initialValue: { + streaks: [], + currentStreak: 0 + }, + in: { + streaks: { + $cond: [{ + $eq: ["$$this.win", true] + }, + "$$value.streaks", + { + $cond: [{ + $gt: [ + "$$value.currentStreak", + 0 + ] + }, + { + $concatArrays: [ + "$$value.streaks", + [ + "$$value.currentStreak" + ] + ] + }, + "$$value.streaks" + ] + } + ] + }, + currentStreak: { + $cond: [{ + $eq: ["$$this.win", true] + }, + { + $add: [ + "$$value.currentStreak", + 1 + ] + }, + 0 + ] + } + } + } + } + } + }, + { + $project: { + streak: { + $cond: [{ + $gt: ["$result.currentStreak", 0] + }, + { + $concatArrays: [ + "$result.streaks", + ["$result.currentStreak"] + ] + }, + "$result.streaks" + ] + } + } + }, + { + $unwind: "$streak" + }, + { + $sort: { + streak: -1 + } + }, + { + $limit: 10 + }, + { + $lookup: { + from: "users", + localField: "_id", + foreignField: "_id", + as: "users" + } + }, + ]); +} + +export default lucky7Leaderboard; + diff --git a/backend/src/api/lucky7.js b/backend/src/api/lucky7.js @@ -1,5 +1,6 @@ import express from "express"; import lucky7BetsCreate from "./lucky7-bets-create.js"; +import lucky7Leaderboard from "./lucky7-leaderboard.js"; import lucky7BetsEvents from "./lucky7-bets-events.js"; import lucky7SessionsCreate from "./lucky7-sessions-create.js"; import auth from "../utils/auth.js"; @@ -9,5 +10,6 @@ const router = express.Router(); router.post("/sessions", auth, lucky7SessionsCreate); router.post("/bets", auth, lucky7BetsCreate); router.get("/bets/:id/events", auth, lucky7BetsEvents); +router.get("/leaderboard", lucky7Leaderboard); export default router;