Reputation: 109
I'm creating a tinder clone. Im currently creating the match/post request in my backend. Within the post request itself it calls a separate function
named match
. This is called after the current user as liked or disliked another account. Basically all I need this function to do is loop through that account's likes to see if it matches the current users id. As I am using MongoDB I need to be able to make use of async await
to interact with my database. However the function
never runs past the if
statement. I'm thinking it has something to do with calling an async function
within .map()
. However I am a bit stumped on how to progress further.
require("dotenv").config();
const express = require("express");
const router = express.Router({ mergeParams: true });
const jwt = require("jsonwebtoken");
const bcryptjs = require("bcryptjs");
const cookieParser = require('cookie-parser');
const { check, validationResult } = require("express-validator");
const multer = require('multer');
const User = require("../models/userSchema");
const ObjectID = require('mongodb').ObjectID;
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/')
},
filename: function (req, file, cb) {
cb(null, Date.now() + '.jpg')
}
})
const upload = multer({ storage: storage })
function asyncHandler(callback) {
return async (req, res, next) => {
try {
await callback(req, res, next);
} catch (error) {
next(error);
console.log(error);
}
};
}
function match (match, user) {
console.log("Starting to match")
const currentUser = user;
console.log(currentUser._id)
match.likes.map((person) => {
return async( req, res, next) => {
console.log(person._id, 'Person id')
console.log(currentUser._id, 'Current user id')
if (person.likes._id === currentUser._id) {
console.log("Worked")
await User.findOneAndUpdate({ _id: new ObjectID(currentUser._id) }, { $push: { matches: match } });
await User.findOneAndUpdate({ _id: match._id },{ $push: { matches: currentUser } });
res.json({ message: "You got a match!" }).end();
}
}
});
};
/*
Adds matches to the user
*/
router.patch( "/user/match/:id", authenticateUser, asyncHandler(async (req, res, next) => {
const errors = validationResult(req);
const user = await User.findOne({ _id: req.params.id });
if (!errors.isEmpty()) {
const errorMessages = errors.array().map((error) => error.msg);
return res.status(400).json({ errors: errorMessages });
}
const updateObject = req.body.likes;
console.log(updateObject)
const likedUser = await User.findOne({ _id: updateObject });
if (updateObject) {
await User.findOneAndUpdate( { _id: req.params.id }, { $push: { likes: updateObject } });
console.log("Getting ready to match")
match(likedUser, user)
} else {
await User.findOneAndUpdate({ _id: req.params.id }, { $push: { dislikes: updateObject } },
function (err, doc) {
if (err) {
return res.json({ success: false, message: err.message });
}
res.json({ updateObject });
return res.status(204).end();
}
);
}
})
);
{
likes: [Array],
dislikes: [],
_id: '60bcfe5191694b0981439707',
firstName: 'Jon',
lastName: 'Doe',
emailAddress: '[email protected]',
password: '$2a$10$cOt9PcLUd7HdwzYjhBAov.OWVGQUbBVVpR2SiVSXghFWaJfX88bSm',
gender: 'Male',
sexualPreference: 'Straight',
age: 26,
description: 'Hello my name is Jon',
path: 'uploads/1622998609804.jpg',
matches: [],
__v: 0
}
The likes array is an array of objects composed like this user object.
Upvotes: 0
Views: 657
Reputation: 36
When we use async
-await
inside array functions like forEach()
, map()
.
forEach()
expects a synchronous function and even when we use async
/await
inside, it just returns multiple promises but not in sequential order.
Solution:
Either use for of loop which does your work sequentially.
If you want to use Array.map()
then put it inside Promise.all()
so that it does your task in parallel.
Example:
await Promise.all(files.map(async (file) => {
// your code here....
}));
Upvotes: 2
Reputation: 469
Hard to replicate without seeing the data, but I wouldn't recommend using .map
in this situation, as you're not returning anything and they don't work well with asynchronous code. I'd use a recursive function like this...
I've used a placeholder fetch request instead of a DB update, but the principle is the same...
const recursive = async (matches, user, run = 0) => {
if (run > matches.length) return
console.log(run)
if (matches[run] === user+1) {
await fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(json => console.log(json))
return recursive(matches, user, run +1)
}
else return recursive(matches, user, run +1)
}
Input...
recursive([1, 2, 3, 4], 2)
Output...
0
1
2
{userId: 1, id: 1, title: "delectus aut autem", completed: false}
3
4
The function won't call itself until the last iteration has finished and it will await for the api call to return something before finishing.
Upvotes: 1