I am developing a web app that finds the nearest users (neighbors) and display their product that they want to buy, they also have the ability to sell.
the app uses node.js, javaScript, mongodb, mongoose.
my problem is with sorting the products. I want to display the products sorted from the nearest users of the loggedIn user to the furthest users but that did not happened, The products were not sorted . I have spent hours but I just could not figure out what is wrong
const Product = require('../models/products')
const User = require('../models/user')
module.exports.index = async (req, res) => {
try {
// get logged in user location
const currentUserLocation = req.user.location.coordinates;
// sorting users
const nearbyUsers = await User.find({
location: {
$near: {
$geometry: {
type: 'Point',
coordinates: currentUserLocation
},
}
}
});
// Get products of nearby users
const products = await Product.find({ author: { $in: nearbyUsers.map(user => user._id) } });
console.log("this is the users log: ",nearbyUsers)
console.log('this is the products log: ',products)
// Render the products on the main page
res.render('products/index', { products });
} catch (error) {
console.error('Error fetching nearby products:', error);
res.status(500).send('Internal Server Error');
}
};
user model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const passportLocalMongoose = require('passport-local-mongoose');
const Product = require("../models/products")
const UserSchema = new Schema({
email: {
type: String,
required: true,
unique: true
},
phoneNumber: Number,
location: {
type: {
type: String,
enum: ['Point'],
required:true
},
coordinates: {
type: [Number],
required:true
}
}})
UserSchema.index({ location: '2dsphere' });
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model('User', UserSchema);
product model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const productSchema = new Schema ({
title:String,
images:[
{
url:String,
filename:String
}
],
price:Number,
description:String,
author:{
type: Schema.Types.ObjectId,
ref:'User'
},
transactionType: {
type: String,
enum: ['sell', 'rent'],
},
status: {
type: String,
enum: ['available', 'sold', 'pending'],
default: 'available' // Default status is available
},
});
module.exports=mongoose.model('Products',productSchema)
the index ejs file
<%- layout ('/layouts/boilerplate') %>
<h1>all products</h1>
<div>
<a href="/products/new">add a product</a>
<a href="/products/borrowing-requests">View Borrowing Requests</a>
</div>
<% for(let product of products) {%>
<div class="card" mb-3>
<div class="row">
<div class="col-md-4">
<img src="<%= product.images[0].url %>" class="img-fluid" alt="Product Image"> </div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title"><%= product.title %></h5>
<p class="card-text"><%= product.price %></p>
<p class="card-text">
<small class="text-secondary"><%= product.description %></small>
</p>
<a class="btn btn-primary" href="/products/<%= product._id %>">view <%= product.title %> </a>
</div>
</div>
</div>
</div>
</div>
<% } %>
the routes
router.route('/')
.get((products.index))
I think that there Is something wrong with the logic of the code here but I can't figure It out, I have provided the code relevant to the problem.
do you think that there Is a better way to do this job?, do I need to use something like using mapbox for the code?
If you have any suggestions, please let me know
Note: The coordinates of users are already in the database
In the existing code shown below, the nearby users - sorted by nearest to farthest, will be available. This sort order is very important, since the products must list based on the same order.
// sorting users
const nearbyUsers = await User.find({ location: { $near: { $geometry: { type: 'Point', coordinates: currentUserLocation }, } } });
In the below code, the products will be retrieved using the array of nearby users. Accordingly the list of products will be available.
// Get products of nearby users
const products = await Product.find({ author: { $in: nearbyUsers.map(user => user._id) } });
...
The issue and one of the possible solutions
Now the issue is that - the sort order of the original NearByUsers list has not been applied in product list. One of the ways to address this issue has been demoed below.
//Sample documents Ordered by nearest-to-farthest resulted by the given query for NearByUsers
const nearbyUsers = [{ _id: 'U2' }, { _id: 'U3' }, { _id: 'U1' }];
//Sample documents resulted from the given query for products with respect to the given users
const products = [
{ _id: 'P2', userid: 'U3' },
{ _id: 'P1', userid: 'U2' },
{ _id: 'P3', userid: 'U1' },
];
// Sorting products based on the original order of NearByUsers
products.map((p) => {
p.nearbyorder = nearbyUsers.findIndex((u) => u._id == p.userid);
return p;
});
products.sort((a, b) => a.nearbyorder - b.nearbyorder);
console.log(products);
OUTPUT:
//Look at the product list which has been sorted in the original
//orders of NearByUsers.
[
{ _id: 'P1', userid: 'U2', nearbyorder: 0 },
{ _id: 'P2', userid: 'U3', nearbyorder: 1 },
{ _id: 'P3', userid: 'U1', nearbyorder: 2 }
]