0

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.
1
  • "match.likes.map((person) => { return async( req, res, next) => { … } })" creates an array of async functions, then does nothing with them. Commented Jun 6, 2021 at 18:29

2 Answers 2

2

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:

  1. Either use for of loop which does your work sequentially.

  2. 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....
}));
Sign up to request clarification or add additional context in comments.

Comments

1

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.

1 Comment

Hello! Thank you for responding, I have updated the question to include the data as requested.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.