I'm developing a Dating App which is similar to Tinder, right now, I'm working on node-express-mongodb-mongoose
server and I'm stuck at a point. The problem is, when the app loads, in homepage, I want to fetch all the profiles excluding mine and the ones' which I have passed (disliked). Below is the route for this function in node:
User Schema:
const userSchema = new mongoose.Schema({
email: {
type: 'string',
unique: [true, 'Email ID already present.'],
required: true,
},
password: {
type: 'string',
required: true,
minlength: 4,
},
displayName: {
type: 'string',
required: false,
default: '',
},
photoURL: {
type: 'string',
required: false,
default: '',
},
job: {
type: 'string',
required: false,
default: '',
},
age: {
type: 'number',
required: false,
default: null,
},
passes: {
type: 'Array',
required: false,
},
likes: {
type: 'Array',
required: false,
},
matches: {
type: 'Array',
required: false,
}
}
);
mongoose.model('User', userSchema);
Fetch Profiles Route:
const id = req.user._id;
try {
const currentUser = await User.findById({_id: id}); // gets the current user
const passes = currentUser.passes; // gets the passed/disliked profiles (array of objects)
const users = await User.find(); // gets all the registered users from db
console.log(passes);
const allUsers = [...passes, ...users]; // combining the 2 arrays
console.log('ALL USERS: ' allUsers);
const usersAfterFilter = allUsers.filter(
(user) => user._id.toString() !== id.toString() // finally filtering because I want to fetch all the profiles excluding mine and the ones' which I have passed.
);
console.log('ALL USERS AFTER FILTER: ' usersAfterFilter);
res.send({'response': 'success', 'data': usersAfterFilter});
} catch (error) {
console.log(error.message);
return res.status(422).send({response : error.message});
}
The following is the log output:
[
[
{
_id: new ObjectId("612131375a7fd116969e298c"),
email: '',
password: '',
displayName: 'Yolo',
photoURL: '',
job: 'CEO of World',
age: 22,
passes: [],
likes: [],
matches: [],
createdAt: 2021-12-12T10:38:47.967Z,
updatedAt: 2021-12-12T10:39:14.943Z,
__v: 0
}
]
]
ALL USERS: [object Object],{
_id: new ObjectId("612131375a7fd116969e298c"),
email: '',
password: '',
displayName: 'Yolo',
photoURL: '',
job: 'CEO of World',
age: 22,
passes: [],
likes: [],
matches: [],
createdAt: 2021-12-12T10:38:47.967Z,
updatedAt: 2021-12-12T10:39:14.943Z,
__v: 0
},{
_id: new ObjectId("61b5d2395a7fd12347ae2994"),
email: '',
password: '',
displayName: 'your actor',
photoURL: '',
job: 'Actor',
age: 25,
passes: [ [ [Object] ] ],
likes: [],
matches: [],
createdAt: 2021-12-12T10:39:46.347Z,
updatedAt: 2021-12-12T10:41:36.627Z,
__v: 0
}
Cannot read properties of undefined (reading 'toString')
As you can see, when I combine the two array for filtering purpose, the ...passes
converts to [object Object]
and hence destroys the purpose of filtering because I cannot compare on the basis of id
anymore.
I would really appreciate if someone could help me here!
CodePudding user response:
...when the app loads, in homepage, I want to fetch all the profiles excluding mine and the ones' which I have passed (disliked).
The following demonstrates how you could get the desired data. Assuming some documents in the collection users
, the following run from the mongo
shell.
Sample Documents:
{ _id: 1, passes: [ 3, 4, 5 ] }, { _id: 2 }, { _id: 3 }, { _id: 4 }, { _id: 5 }, { _id: 9 }
Note that the current user is with _id: 1
with passes: [ 3, 4, 5 ]
. The output would be the ids: [ 2, 9 ]
.
The Queries:
You can use any one of the following approaches to get the desired result. The first way:
var currentUser = db.users.findOne({ _id: 1 });
var passedUsers = currentUser.passes;
var allUsers = db.users.find().toArray();
passedUsers.push(currentUser._id);
allUsers.filter(user => (passedUsers.findIndex(passedUser => user._id == passedUser)) == -1)
The output: [ { "_id" : 2 }, { "_id" : 9 } ]
The second approach:
var currentUser = db.users.findOne({ _id: 1 });
var passedUsers = currentUser.passes;
passedUsers.push(currentUser._id);
db.users.find( { _id: { $nin: passedUsers }} ).toArray();
The third way, and this uses a single aggregation query:
db.users.aggregate([
{
$match: { _id: 1 }
},
{
$lookup: {
from: "users",
let: { idVar: "$_id" , passesVar: "$passes" },
pipeline: [
{
$match: {
$expr: {
$not: { $in: [ "$_id", { $concatArrays: [ "$$passesVar" , [ "$$idVar" ] ] } ] }
}
}
},
],
as: "usersAfterFilter"
}},
{
$project: {
usersAfterFilter: 1,
_id: 0
}}
])
The output: { "usersAfterFilter" : [ { "_id" : 2 }, { "_id" : 9 } ] }