I am looking for a right database that supports location based search, found MongoDB supports GeoJSON Objects.
This is a Store Locator application, where user can look around and choose Store that's near to him for ordering products.
Simple Vendor schema :
const VendorSchema = new Schema({
address: {
type: String,
required: [true, 'Please add address']
},
formattedAddress: {
type: String
},
location: {
type: {
type: String,
enum: ['Point']
},
// GeoJSON Points
coordinates: {
type: [Number],
index: '2dsphere'
},
formattedAddress: String,
street: String,
city: String,
state: String,
zipcode: String,
country: String
},
createdAt: {
type: Date,
default: Date.now
}
});
Database will have many FMCG Products that multiple Vendors could be selling.
Product Schema :
const ProductSchema = new Schema({
name: {
type: String,
required: true
},
desc: {
type: String,
required: true
},
price: Number,
createdAt: {
type: Date,
default: Date.now
}
});
A Vendor can sell multiple Products and a Product could be sold by many Vendors, there's
N-to-N
relationship between Vendors & Products.
So was thinking of creating a new Schema, VendorProduct Schema :
const VendorProductSchema = new Schema({
price: Number,
discountVal: Number,
vendor : {
type: ObjectId,
ref: 'Vendor'
},
createdAt: {
type: Date,
default: Date.now
}
});
This is where its getting tricky / challenging :
User's can either look-up for Vendor/Stores around them or can also directly search for a Product.
If asked to find Vendors, its straight look up in the Vendors collection with-in certain Radius.
Vendor.find({"location.coordinates": {$geoWithin: {$centerSphere: [[User long, User lat], 1/6378.15]}}})
But when user searches for a Product :
System should send back searched Product(s) details along with near by Vendors who are selling them - from closest to farthest, in certain radius.
For this reason i was thinking of storing Vendor's GeoJSON location details for a Product in VendorProduct schema.
VendorProduct Schema with GeoJSON details :
const VendorProductSchema = new Schema({
price: Number,
discountVal: Number,
vendor : {
type: ObjectId,
ref: 'Vendor'
},
location: {
type: {
type: String,
enum: ['Point']
},
// GeoJSON Points
coordinates: {
type: [Number],
index: '2dsphere'
}
},
createdAt: {
type: Date,
default: Date.now
}
});
Let's say user searches with keyword ONIONS. It will be found in Products collection, will use ProductID and in-turn filter them in VendorProducts collection based on Geo co-ordinates. In that way i can pull Product info like description, images from Products collection & Vendor, Prices info from VendorProducts collection.
This is only keeping in mind, a single Product can be sold by multiple Vendors. When user searches with a Product name - there could be N number of sellers of this product at different prices. But to find only closest vendors, was thinking of storing Vendor location details against Product in VendorProductSchema.
FEW QUESTIONS :
As per my understanding, you should only save the location coordinates in Vendor Schema only, because they are related to vendors. Your old VendorProduct Schema is fine
Case1: User is looking for nearby vendors
You need to run a query to find the vendors on the basis of the user's location and provide the vendors listing to the user
For that, you need to run
Vendor.find({"location.coordinates": {$geoWithin: {$centerSphere: [[User long, User lat], 1/6378.15]}}})
Case2: User is looking for products he/she can find nearby
In that case, also search for nearby vendors first by the above query (Remember there will be limited no of vendors nearby, if not you need to reduce the search radius).
Once you get all the nearby vendors, save their ids in an array, let's call it
vendorArray = [vendor_id1, vendor_id2.....]
Then search for products in VendorProduct schema
VendorProduct.find({
vendor : {
$in: vendorArray
}
})
The above solution was just for an alternative to store location information in VendorProductSchema
Now you need to get the product details after getting product ids from vendorProduct collection, I would suggest you should add product name or any other field in vendorProduct by which you want to search or filter
Downside of current approach There are few downsides storing location coordinates in VendorProduct