How $geoNear chooses the field of the model to find the coordenates in MongoDB? - mongodb

I'm using mongoose and I'm trying to get activities from the schema 'Activity' with an specific filter using $geoNear, but it always returns an empty array and I think it's because the aggregate function is not finding the coordenates of my model.
This is an example of the JSON to send:
{
"coordinates": {
"lat": 37.3890924,
"lon": -5.984458899999936
},
"distance": 100000000
}
This is the query:
Activity.aggregate([
{ $geoNear: {
near: {
type: "Point",
coordinates: [req.body.coordinates.lon, req.body.coordinates.lat]
},
maxDistance: req.body.distance * 1000,
spherical: true,
distanceField: "distance"
}
}
])
And this is the schema, where the coordinates are into the field 'meetingPoint':
const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate');
const Schema = mongoose.Schema;
var ActivitySchema = Schema({
title: {type: String, require: true },
meetingPoint: {
meet_name:{type: String, require: true },
coordinates: {
lat: {type: Number, require: true },
lon: {type: Number, require: true }
}
},
date: {type: Date, require: true },
car: Boolean,
sites: {type: Number, min: 0 },
price: {type: Number, min: 0.0, require: true },
description: String,
eventTime: String,
event: Boolean,
sport: {type: Schema.Types.ObjectId, ref: 'Sport', require: true },
owner: {type: Schema.Types.ObjectId, ref: 'User', require: true },
attenders: [{type: Schema.Types.ObjectId, ref: 'User'}],
comments: [{type: Schema.Types.ObjectId, ref: 'Comment'}],
ratings: [{
rating:{type: Number},
user: {type: Schema.Types.ObjectId, ref:'User'}
}],
creationDate: {type: Date, default: Date.now, require: true },
updateDate: {type: Date, default: Date.now, require: true },
public: Boolean,
image: String
});
ActivitySchema.plugin(mongoosePaginate);
ActivitySchema.index({location: "2dsphere"});
module.exports = mongoose.model('Activity', ActivitySchema);
EDIT: I changed the coordinates in mongoose schema to the GeoJSON format(I think) and now they look like this:
meetingPoint: {
meet_name:{type: String, require: true },
coordinates: {
type: String,
coordinates: []
}
}
But the result is the same.
EDIT2: I also updated the existing data in the collection according to the meetingPoint with the pertinent format. This is an example:
"_id" : ObjectId("5ac36a2aasdsd3242b"),
"meetingPoint" : { "meet_name" : "Av. de Menéndez Pelayo, 76, 41030 Madrid, España", "coordinates" : { "type" : "Point", "coordinates" : [ -5.984458899
9936, 37.3890924 ] } },
"attenders" :....
But I still receive no activities with the filter.

Related

populate or aggregator, how?

I want to get only all messages related to the projects posted by user.
I don't think there is a way to do so using populate because we have to get the user id from the other collection and then render messages using his id which is "submittedBy" in the project schema.
I am trying aggregator but it is also not working.
Any help or clue would be appreciated.
message Schema:
const MessageSchema = new Schema({
content:{
type: String,
trim: true
},
projectId:{
type: Schema.Types.ObjectId,
ref: 'Form'
},
imageId:{
type: Schema.Types.ObjectId,
ref: 'Image'
},
sender:{
type: Schema.Types.ObjectId,
ref: 'User'
},
readBy:[{
type: Schema.Types.ObjectId,
ref: 'User'
}],
}, {timestamps:true});
Project schema:
const FormSchema = new Schema({
submittedBy: {
type: Schema.Types.ObjectId,
ref: 'User'
},
logoName: {
type: String,
trim: true
},
industry: [{
type: String,
trim: true
}],
logoType: [{
type: String,
trim: true
}],
colors: [{
type: String,
trim: true
}],
tagline: {
type: String,
trim: true
},
org: {
type: String,
trim: true
},
communicate: {
type: String,
trim: true
},
deadline : {
type: String,
trim: true
},
services: {
type: String,
trim: true
},
package: {
type: String,
trim: true
},
assignedTo: {
type: String,
trim: true
}
}, {timestamps:true})
I tried population but I don't think it will work or efficient.
So I am using aggregation but it's not working:
var objId = mongoose.Types.ObjectId(req.session.user._id);
results = await Model.aggregate([
{
$lookup:
{
from: "forms",
localField: "projectId",
foreignField: "_id",
as: "tags"
}
},
{ $unwind: "$tags" },
{$match:{ 'tags.submittedBy': userId }},
]).exec(function(err, results) {
console.log(results)
});
Result After Combining two collections:
{
_id: 609bd3772583c56dd3e302d3,
readBy: [],
content: 'Remove Tagline and align.',
sender: 604db5708cf232652cd4469e,
imageId: 6099964c2583c56dd3e302c3,
projectId: 60968eed2583c56dd3e302ac,
createdAt: 2021-05-12T13:09:11.060Z,
updatedAt: 2021-05-12T13:09:11.060Z,
__v: 0,
tags: {
_id: 60968eed2583c56dd3e302ac,
industry: [Array],
logoType: [Array],
colors: [Array],
logoName: 'global consultancy services',
tagline: 'Follow your dreams',
org: 'We guide students who seeks to study overseas e.g. the UK. We offer consultancy services to students from selecting a university to getting visa and then getting in the country.',
communicate: '3 concepts\r\n' +
'Keep "Indra global " big AND bold\r\n' +
'and "consultancy services" below it.\r\n' +
'In one concept you can use IGCS initials to create icon form'
deadline: '2021-05-12',
services: '',
package: 'undefined',
submittedBy: 60968eed2583c56dd3e302ab,
createdAt: 2021-05-08T13:15:25.661Z,
updatedAt: 2021-05-10T08:28:18.587Z,
__v: 0,
assignedTo: '6050d8485cc8bb6a20ef36fa'
}
}
]

Mongoose - Sub Document Array Issue

I have a "Company" Model which has a number of "Rooms".
I'm able to create the Rooms no problem, and they have a link back to the Company.
The problem is that when I get the Company, the Rooms array has no items.
I can see that the Room exists and has a link back to the Company:
{
"RoomType": 0,
"AllowedRoomRoles": [
"5f999f4f542eed1b8fce5fa9"
],
"Enabled": true,
"_id": "5fb677b453658c7070bf9433",
"RoomName": "Martins Room 2",
"RoomPin": "0001",
"Company": "5fad553db19ca100161a0d8f",
"__v": 0
}
However when I do:
var company = await CompanyModel.findById('5fad553db19ca100161a0d8f');
I get the Company back but the Rooms array has no items in it.
Here are my models:
//Room Schema:
const roomSchema = new Schema({
RoomPin: String,
RoomName: String,
RoomType: { type: RoomType, default: RoomType.MeetingRoom } ,
Company: {type: Schema.Types.ObjectId, ref: 'CompanySchema'},
AllowedRoomRoles: [{type: Schema.Types.ObjectId, ref: 'RoomRoleSchema'}],
Enabled: { type: Boolean, default: true },
}, {
collection: "room"
})
//Company Schema:
const companySchema = new Schema({
CompanyName: { type: String, required: true },
CompanyLogo: { type: String, required: true },
Enabled: { type: Boolean, default: true },
CompanyIdentifier: { type: String, required: true },
CompanyWebsite: { type: String, required: true },
Rooms: [{type: Schema.Types.ObjectId, ref: 'RoomSchema'}],
}, {
collection: "company"
})
Minor update:
Seems doing it this way around is fine?
```var rooms = await RoomModel.find({'Company': company._id.toString() });

Is it possible to have two types of objects in an array of mongoose schema

I am building an e-commerce application and this is my orders schema.
const mongoose = require("mongoose");
const orderSchema = new mongoose.Schema({
buyer: {
type: mongoose.Schema.Types.ObjectId,
ref: "buyer",
required: true
},
items: [{
item: {
type: mongoose.Schema.Types.ObjectId,
ref: "item",
},
quantity: {
type: Number,
default: 1
}}
],
seller: {
type: mongoose.Schema.Types.ObjectId,
ref: "seller",
required: true
},
location: {
type: {
type: "String",
enum:['Point']
},
coordinates: {
type: [Number],
index: '2dsphere'
}
},
sendAt:{
type: Date,
default: Date.now
}
});
const orderModel = mongoose.model("orders", orderSchema);
module.exports = orderModel;
I want to have an array having item-reference-id and quantity.
But with the above schema when i enter data, each item is acting as an another sub-document and having _id. Query response image.
I have found solution:
order: [
{
_id: false,
item: {
type: mongoose.Schema.Types.ObjectId,
ref: "items",
required: true,
},
quantity: { type: Number },
},
],
_id: false will stop the subdocument from creating another id for the subdocument.

How to store range(in geocircle radius form) in mongoose schema

I am building an e-commerce application. Every store has a delivery range so i want to set delivery range of every store in the database to show the store only to those who falls in the delivery range.
Store Schema.
const mongoose = require("mongoose");
const sellerSchema = new mongoose.Schema({
name:{
type: String,
required: true,
},
type: {
type: String,
required: true
},
location: {
type: {
type: "String",
enum:['Point']
},
coordinates: {
type: [Number],
index: '2dsphere'
}
},
owner: {
type: String,
required: true
},
items: [{
type: mongoose.Schema.Types.ObjectId,
ref: "items"
}],
contact: {
type: String,
required: true
},
loginId: {
index:true,
unique: true,
type: String,
},
password: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now
}
});
const sellerModel = mongoose.model("sellers",sellerSchema);
module.exports = sellerModel;

.where() by populated fields

I want to find the closest workers by his location which have a specific skill.
Location schema:
var schema = Schema({
name: String,
type: String, // home | latest
user: {type: Schema.Types.ObjectId, ref: 'User'},
address: String,
position: {
type: {type: String, default: 'Point'},
coordinates: [Number]
},
status: String // active | inactive
}, {collection: 'locations'});
Worker schema:
var schema = Schema({
username: String,
password: String,
firstName: {type: String, default: ''},
middleName: {type: String, default: ''},
lastName: {type: String, default: ''},
role: {type: String, default: 'user'}, // admin | user | worker
skills: [{
object: {type: Schema.Types.ObjectId, ref: 'Skill'},
slug: String, // Should remove in the future
ratePerHour: Number,
status: {type: String, default: 'active'} // active | inactive
}],
locations: [{type: Schema.Types.ObjectId, ref: 'Location'}]
}, {collection: 'users'});
Skill schema:
var schema = Schema({
name: String,
slug: String,
users: [{type: Schema.Types.ObjectId, ref: 'User'}],
isFeatured: Boolean,
minRatePerHour: Number,
maxRatePerHour: Number,
status: String // active | inactive | deleted
}, {collection: 'skills'});
Bellow is my query but .where() does not work with populated field.
Location
.find({
'position': {
$near: {
$geometry: {type: 'Point', coordinates: [lat, lng]},
$minDistance: 0,
$maxDistance: 20000
}
}
})
.populate('user')
.deepPopulate('user.skills.object')
.where({'user.skills': {$elemMatch: {'object.slug': 'cleaning'}}})
.limit(5)
.exec(callback);
Am I doing wrong with these schemas? Should I use embed document rather than ID reference?
Is there any way else to query?
You have to use special properties for populate as described here: Query conditions and other options
So I think you can get your results with something like this:
Location
.find({
'position': {
$near: {
$geometry: {
type: 'Point',
coordinates: [lat, lng]
},
$minDistance: 0,
$maxDistance: 20000
}
}
})
.populate({
path: 'user',
match: {
'skills': {
$elemMatch: {
'object.slug': 'cleaning'
}
}
},
options: {
limit: 5
}
})
.deepPopulate('user.skills.object')
.exec(callback);
Not tested, keep it only as example.