MONGODB store value in variable to use later - node.js

i have a code that inserts information from a 3rd party API every 24hours the api information is ID, Name, Status, Position, Score the only information that can get updated if there is any change are Name, Status, Position, Score, ID will always be the same.
I'm trying to show information based on if there is any change when new data is inserted to the database for example
08/14/2022 ------------- 08/15/2022
Name: yandr1 ========== NO CHANGES
position 1 ========== NO CHANGES
id 123 ========== NO CHANGES
score 100 ========== CHANGES TO: 200 ( POINTS GAINED 100 )
based on the new data inserted to MongoDB Database Score changed from 100 to 200, how can i show on the website the OLD SCORE AND POINTS GAINED? Position, Name,old score, POINTS GAINED
CODE TO INSERT DATA INTO DB FROM API
//POST DAILY PLAYERS DATA//
cron.schedule('56 23 * * *', async () => {
const postSchema = new mongoose.Schema({
id: {
type: Number,
required: true
},
name: {
type: String,
required: true
},
status: {
type: String,
required: false
},
});
const Post = mongoose.model('players', postSchema);
async function getPosts() {
const getPlayers = await fetch("http://localhost:3008/api/players");
const response = await getPlayers.json();
for (let i = 0; i < response.players.length; i++) {
const post = new Post({
id: response.players[i]['id'],
name: response.players[i]['name'],
status: response.players[i]['status'],
});
post.save();
}
}
console.log("Table submitted successfully")
await getPosts();
});
//POST DAILY HIGHSCORE DATA//
cron.schedule('55 23 * * *', async () => {
const postSchema = new mongoose.Schema({
position: {
type: Number,
required: false
},
id: {
type: Number,
required: true
},
score: {
type: Number,
required: false
},
});
const Post = mongoose.model('highscores', postSchema);
async function getPosts() {
const getHighscore = await fetch("http://localhost:3008/api/highscore/players");
const response = await getHighscore.json();
for (let i = 0; i < response.players.length; i++) {
const post = new Post({
position: response.players[i]['position'],
id: response.players[i]['id'],
score: response.players[i]['score'],
});
post.save();
}
}
console.log("Table submitted successfully")
await getPosts();
});
router.get('/export', async function(req, res, next) {
let data
try {
data = await Promise.all([
Posts.list(),
Events.list(),
Messages.list(),
Users.list()
]);
// at this point, data is an array. data[0] = Posts.list result, data[1] = Events.list result etc..
res.status(200).json(data)
} catch (e) {
res.status(500).send('error');
}
});

Hey Yandry try this code-
async function getPosts() {
const getPlayers = await fetch("http://localhost:3008/api/players");
const response = await getPlayers.json();
for( let i = 0;i < response.players.length; i++){
id= response.players[i]['id'];
name= response.players[i]['name'];
status= response.players[i]['status'];
const updateScore = await findOneAndUpdate({id:id},{$set:{name:name,status:status}})
console.log("Updated Score",updateScore)
}
}
Please, try this code, hope you will get solution, if you still facing issue just lemme know, i will help you more.
Thank

Related

MongoDB UpdateMany Method

how can i use the update Many Method inside my code?. Right now this code will insert the data over and over inside the table, i need to make it so it will update the old data and add new data if new data is available in the third party api. I'm new to MongoDB any help will be much appreciate it! thanks.
cron.schedule('0 0 * * *', async () => {
const postSchema = new mongoose.Schema({
id: {
type: Number,
required: true
},
name: {
type: String,
required: true
},
status: {
type: String,
required: false
},
});
const Post = mongoose.model('players', postSchema);
async function getPosts() {
const getPlayers = await fetch("http://localhost:3008/api/players");
const response = await getPlayers.json();
for( let i = 0;i < response.players.length; i++){
const post = new Post({
id: response.players[i]['id'],
name: response.players[i]['name'],
status: response.players[i]['status'],
});
post.save();
}
}
console.log("Task submitted successfully")
await getPosts();
});
what i was thinking
const post = await Post.updateMany({
id: response.players[i]['id'],
name: response.players[i]['name'],
status: response.players[i]['status'],
});
I believe you can use bulkWrite and inside bulkWrite you can write updateOne operation with the upsert flag set to true
You can construct an array of operations as follows
let operations = [];
for (let player of players) {
operations.push({
updateOne: {
filter: { id: player.id },
update: { $set: { name: player.name } },
upsert: true,
}
})
}
And finally you can make a call to bulkWrite. Please read the documentation for the operations above

Mongo DB SORTING data nodejs

i created a code that Backsup/Deletes and Inserts information from the Third Party API every 24hours to update the Third party api changes daily on the database.
how can i sort the information i get from the MongoDB by which score changed the most?
API LOOKS LIKE
{
"_id": "6365e1dbde0dd3639536f4b7",
"position": 1,
"id": "105162",
"score": 2243536903,
"__v": 0
},
MY CODE
app.get('/api/TopFlops', async (req, res) => {
const topflops = await TopFlops.find({}).sort({_id: +1}).limit(5)
res.json(topflops);
})
CODE TO INSERT DATA FROM THE 3RD PARTY API TO DB
cron.schedule('59 23 * * *', async () => {
const postSchema = new mongoose.Schema({
id: {
type: Number,
required: true
},
name: {
type: String,
required: true
},
status: {
type: String,
required: false
},
});
const Post = mongoose.model('players', postSchema);
async function getPosts() {
const getPlayers = await fetch("http://localhost:3008/api/players");
const response = await getPlayers.json();
for( let i = 0;i < response.players.length; i++){
const post = new Post({
id: response.players[i]['id'],
name: response.players[i]['name'],
status: response.players[i]['status'],
});
post.save();
}
}
console.log("Table submitted successfully")
await getPosts();
});
CODE TO FETCH API
const [playerName, setPlayerName] = useState([]);
const [playerRank, setPlayerRank] = useState([]);
const [player, setPlayer] = useState([]);
const [perPage, setPerPage] = useState(10);
const [size, setSize] = useState(perPage);
const [current, setCurrent] = useState(1);
const [players, setPlayers] = useState();
const fetchData = () => {
const playerAPI = 'http://localhost:3001/api/topflops';
const playerRank = 'http://localhost:3001/api/topflops';
const getINFOPlayer = axios.get(playerAPI)
const getPlayerRank = axios.get(playerRank)
axios.all([getINFOPlayer, getPlayerRank]).then(
axios.spread((...allData) => {
const allDataPlayer = allData[0].data
const getINFOPlayerRank = allData[1].data
const newPlayer = allDataPlayer.map(name => {
const pr = getINFOPlayerRank.find(rank => name.id === rank.id)
return {
id: name.id,
name: name.name,
alliance: name.alliance,
position: pr?.position,
score: pr?.score
}
})
setPlayerName(allDataPlayer)
setPlayerRank(getINFOPlayerRank)
console.log(getINFOPlayerRank)
console.log(newPlayer)
setPlayer(newPlayer)
})
)
}
useEffect(() => {
fetchData()
}, [])
const getData = (current, pageSize) => {
// Normally you should get the data from the server
return player?.slice((current - 1) * pageSize, current * pageSize);
};

Mongoose and express insert many many-to-many relationships in one request

I want to make a request in which I add several meals to order and a request that removes several meals from order. It is many-to-many relationship because order can have several meals and meal can have several orders.
This is my order model:
const mongoose = require("mongoose");
const orderObject = {
cook: { type: mongoose.Types.ObjectId, ref: "CookRoleUser" },
remark: { type: String },
delivery_address: { type: String, required: true },
orderer: {
type: mongoose.Types.ObjectId,
ref: "RegularRoleUser",
required: true,
},
meals: [{ type: mongoose.Types.ObjectId, ref: "Meal" }],
active: { type: Boolean, default: true },
date_ordered: { type: Date, default: () => Date.now() },
};
const Order = mongoose.model("Order", new mongoose.Schema(orderObject));
module.exports = { Order };
And this is my meal model:
const mongoose = require("mongoose");
const mealCategories = {
MAIN: "MAIN",
DESSERT: "DESSERT",
APPETIZER: "APPETIZER",
DRINK: "DRINK",
};
const mealTypes = {
REGULAR: "REGULAR",
SPECIAL: "SPECIAL",
};
const mealObject = {
name: { type: String },
ingredients: [
{ name: { type: String }, allergen: { type: Boolean, default: false } },
],
is_offered: { type: Boolean, default: false },
orders: [{ type: mongoose.Types.ObjectId, ref: "Order" }],
cook: { type: mongoose.Types.ObjectId, ref: "CookRoleUser" },
category: {
type: String,
enum: Object.values(mealCategories),
default: mealCategories.MAIN,
},
type: {
type: String,
enum: Object.values(mealTypes),
default: mealTypes.REGULAR,
},
date_created: { type: Date, default: () => Date.now() },
};
const mealSchema = new mongoose.Schema(mealObject);
const Meal = mongoose.model("Meal", mealSchema);
module.exports = { Meal, mealTypes };
I've tried to do this:
For addition:
const addMealsToOrder = async (req, res, next) => {
const order = await Order.findById(req.body.orderId);
let mealCount = 0;
await req.body.mealIds?.forEach(async (mealId, index) => {
const meal = await Meal.findById(mealId);
if (order.meals.includes(mealId)) {
return next(
new HttpError(
`Meal ${meal.name} already in order ${order.remark}.`,
400
)
);
}
if (order.cook.toString() != meal.cook.toString()) {
return next(
new HttpError(
`Meal ${meal.name} cook not same as order ${order.remark} cook.`
)
);
}
meal.orders.push(order.id);
order.meals.push(meal.id);
await meal.save();
mealCount = index;
});
if (mealCount == req.meals.length - 1) {
order.save();
res.json(order);
}
};
or without checking is are meals already in order and are cooks the same:
const addMealToOrderTest = async (req, res, next) => {
await req.body.mealIds.forEach(async (mealId) => {
const order = await Order.findById(req.body.orderId);
const meal = await Meal.findById(mealId);
order.meals.push(mealId);
meal.orders.push(order.id);
await order.save();
await meal.save();
});
res.json(2);
};
And for deletion:
const removeMealsFromOrder = async (req, res, next) => {
const { orderId, mealIds } = req.body;
const order = await Order.findById(orderId);
await req.body.mealIds.forEach(async (mealId, index) => {
const meal = Meal.findById(mealId);
meal.orders = meal.orders.filter((oId) => oId != order.id);
order.meals = order.meals.filter((mId) => mId != mealId);
await meal.save()
});
await order.save()
res.json(order);
};
I've tested adding and deleting in postman. Behaviour is very weird and random. Some times it does not add meals, or adds only few, etc. I test the result by fetching single order and/or single meal.
My question:
What is the best way to implement many-to-many update where you want to add for a single entity (order) multiple entities (meals)?
Furthermore I would also want to check, in addtion request, does the certain meal already exist in that order and are the order cook and certain meal cook not the same. If some of these condition is true, I want to inform the request issuer about it and stop all adding and in deletion request does the order contain certain meal and also inform the request issuer if that is true.
EDIT 04/08/22
Now i've tried to make my controllers as such
Addition
const addMealToOrderTest = async (req, res, next) => {
const { orderId, mealIds } = req.body;
await mealIds.forEach(async (mealId) => {
const order = await Order.findById(orderId);
const meal = await Meal.findById(mealId);
order.meals.push(mealId);
meal.orders.push(order.id);
await order.save();
await meal.save();
});
res.json(2);
};
Removal
const removeMealsFromOrder = async (req, res, next) => {
const { orderId, mealIds } = req.body;
await mealIds.forEach(async (mealId) => {
const order = await Order.findById(orderId);
const meal = await Meal.findById(mealId);
order.meals.pull(mealId);
meal.orders.pull(orderId);
await order.save();
await meal.save();
});
res.json(2);
};
Behaviour is very random. Sometimes it works all fine but sometimes I get:
VersionError if order.save() is in mealIds.forEach function or
ParrallelSaveError if the fetching and saving of the order are outside mealIds.forEach function.
EDIT no:2 04/08/22
Addition
const addMealToOrderTest = async (req, res, next) => {
const { orderId, mealIds } = req.body;
const order = await Order.findById(orderId);
let addedMealCount = 0;
mealIds.forEach((mealId) => {
if (!order.meals.includes(mealId)) {
order.meals.push(mealId);
addedMealCount += 1;
}
});
if (addedMealCount != mealIds.length) {
return res.json({ error: "Meal already in that order" });
}
await mealIds.forEach(async (mealId) => {
const meal = await Meal.findById(mealId);
if (!meal.orders.includes(mealId)) {
meal.orders.push(order.id);
await meal.save();
}
});
await order.save();
res.json(order);
};
Removal
const removeMealsFromOrder = async (req, res, next) => {
const { orderId, mealIds } = req.body;
const order = await Order.findById(orderId);
mealIds.forEach((mealId) => {
order.meals.pull(mealId);
});
await mealIds.forEach(async (mealId) => {
const meal = await Meal.findById(mealId);
meal.orders.pull(orderId);
await meal.save();
});
await order.save();
res.json(order);
};
Addition and removal both seem to work now. But I am wondering how could I check is meal cook and order cook the same when I add meals to order.
Problem with this is that I would have to fetch each meal, and then check are cooks the same as in the order.
When I do so, usually I get Cannot set headers or such. I've tried to initialize counter before forEach loop in which I fetch an meal for mealId and increment it only if cooks are the same. And if they are not, counter is not incremented and response is sent. I sent an ok response with order only if the counter is the same as mealIds length. But, counter does not seem to change if I fetch meal by id.

Mongoose post save hook, modifiedPaths() is always empty

Our aim is to have a post hook in place where we can track changed fields.
Model file:
const VariationSchema = new Schema({
_id: {
type: String,
},
title: {
type: String,
},
desc: {
type: String,
},
});
VariationSchema.post('save', async function (doc) {
console.log(doc.modifiedPaths());
});
const VariationModel = mongoose.model('variation', VariationSchema);
module.exports = {
VariationModel,
VariationSchema,
};
Service file:
const variationDocument = await VariationModel.findById(variationId).select({});
variationDocument.desc = (Math.random() + 1).toString(36).substring(7);
await variationDocument.save();
return variationDocument.toJSON();
No matter what we do, doc.modifiedPaths() is always empty. Please help

How should I change the value of the field before saving it to database?

I am new to Node.js and I'm trying to perform CRUD operation right now. I have this function to save data to the mongoDB database but the thing is I'm trying to change the value of one particular field before saving it to database. The problem is that my data is getting saved first and then the calculations are being performed. Here is my post function:
router.post('/', async(req, res) => {
const reservation = new Reservation({
guestID: mongoose.Types.ObjectId(req.body.guestID),
roomID: mongoose.Types.ObjectId(req.body.roomID),
checkIn: req.body.checkIn,
checkOut: req.body.checkOut,
numberOfAdults: req.body.numberOfAdults,
totalCost: req.body.totalCost,
numberOfChildren: req.body.numberOfChildren
})
try
{
const reservationRecord = await reservation.save()
res.json(reservationRecord)
}
catch(err)
{
console.log(err)
res.send("Error")
}
})
And here is the Schema
const mongoose = require('mongoose')
const axios = require('axios')
const reservationSchema = new mongoose.Schema({
guestID: {
type: mongoose.SchemaTypes.ObjectId,
required: true
},
roomID: {
type: mongoose.SchemaTypes.ObjectId,
required: true
},
checkIn: {
type: Date,
required: true
},
checkOut: {
type: Date,
required: true
},
numberOfAdults: {
type: Number,
required: true
},
numberOfChildren: {
type: Number,
required: true
},
totalCost: {
type: Number,
required: false,
default: 0
}
})
reservationSchema.pre('save', function(next){
var date1 = new Date(this.checkIn);
var date2 = new Date(this.checkOut);
var diff = Math.abs(date1.getTime() - date2.getTime());
var diffDays = Math.ceil(diff / (1000 * 3600 * 24));
console.log(diffDays)
var roomCost
var totalRoomCost
axios.get("http://localhost:5555/rooms/" + this.roomID).then((response) => {
console.log(response)
roomCost = response.data.cost;
console.log("room cost is " + roomCost)
totalRoomCost = (this.numberOfAdults + this.numberOfChildren) * response.data.cost * diffDays
this.totalCost = totalRoomCost
})
//this.totalCost = (this.numberOfAdults + this.numberOfChildren) * roomCost * diffDays
console.log(this.totalCost)
next()
})
const Reservation = mongoose.model('reservation', reservationSchema)
module.exports = Reservation
I want to change the value of totalCost before saving it to database. Can somebody let me know what the problem is with the code?
Thank you!
You should just handle the calculations in your POST method, before your create your new Reservation instance:
router.post('/', async (req, res) => {
try {
const {
numberOfChildren,
numberOfAdults,
roomID,
checkIn,
checkOut,
} = req.body;
var date1 = new Date(checkIn);
var date2 = new Date(checkOut);
var diff = Math.abs(date1.getTime() - date2.getTime());
var diffDays = Math.ceil(diff / (1000 * 3600 * 24));
const room = await Room.findById(roomID)
const newTotalCost = (numberOfAdults + numberOfChildren) * room.cost * diffDays;
const reservation = new Reservation({
...req.body,
totalCost: newTotalCost,
});
const reservationRecord = await reservation.save();
res.json(reservationRecord);
} catch (err) {
console.log(err);
res.send('Error');
}
});
Of course, the reservationSchema.pre('save') function is unecessary in this case.

Resources