Related
I am new to mongo and NodeJS and have a use case where I want to get filtered results from multiple collection.
Advance apologies for the long post.
for ex:
collectionA
{
"_id" : "foo#gmail.com",
"name" : "Foo",
"location" : {
"coordinates" : [
-122.420170,
37.780080
],
"type" : "Point"
}
},
{
"_id" : "bar#gmail.com,
"name" : "Bar",
"location" : {
"coordinates" : [
-122.420060,
37.780180
],
"type" : "Point"
}
}
collectionB: Some attributes are not present for all the documents and hence optional
{
"_id" : "foo#gmail.com"
"AttributeA" : [
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Foo"
},
{
"name" : "AttA_Name1",
"val" : "Coll_B_AttA_Val_Foo"
}]
},
{
"_id" : "bar#gmail.com"
"AttributeA" : [
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Bar"
},
{
"name" : "AttA_Name2",
"val" : "Coll_B_AttA_Val_Bar"
}
],
"AttributeB" : [
{
"name" : "AttB_Name",
"val" : "Coll_B_AttB_Val_Bar"
}
]
}
CollectionC: Some attributes are not present for all the documents and hence optional
{
"_id" : "foo#gmail.com"
"AttributeA" : [
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Foo"
}]
},
{
"_id" : "bar#gmail.com"
"AttributeA" : [
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Bar"
}
],
"AttributeB" : [
{
"name" : "Coll_C_AttB_Name",
"val" : "Coll_C_AttB_Val_Bar"
}
]
}
I know Collection B and C schema looks the same but the purpose is different and they have to be different. DB design is not the question so I would appreciate if do not put all the focus on it.
Query:
Assume there is another user (Alan) with same attributes present as Bar that exist in the collection but is not living nearby the location of Bar.
The query I am trying to build on top of these is,
Find people living nearby from CollectionA
And Collection B, if AttributeA exist and have an element with name: AttA_Name
And in Collection C, if AttributeA exist and have an name: Coll_C_AttA_Name
In the above case I am expecting a result as
{
"_id" : "foo#gmail.com",
"name" : "Foo",
"location" : {
"coordinates" : [
-122.420170,
37.780080
],
"type" : "Point"
},
"collectionB_AttributeA" : [
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Foo"
},
{
"name" : "AttA_Name1",
"val" : "Coll_B_AttA_Val_Foo"
}]
,
"collectionC_AttributeA" : [
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Foo"
}]
},
{
"_id" : "bar#gmail.com,
"name" : "Bar",
"location" : {
"coordinates" : [
-122.420060,
37.780180
],
"type" : "Point"
},
"collectionB_AttributeA":[
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Bar"
},
{
"name" : "AttA_Name2",
"val" : "Coll_B_AttA_Val_Bar"
}
],
"collectionC_AttributeA":[
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Bar"
}
]
}
There is one way of doing is in parts:
query Collection A and get the nearby people
Loop through the result of 1 and find in CollectionB if they have AttributeA and an element with name AttA_Name and eliminate if they don't match.
Loop through the filtered results from 2 and find in CollectionC if they have AttributeA and and element with name Coll_C_AttA_Name and if they don't eliminate such documents.
Is there a way I can use aggregate to build this query as one? I tried reading and trying the aggregate but seems like my understanding is incomplete.
let result = await CollectionASchema.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [ Number(long) , Number(lat) ] },
distanceField: "dist.calculated",
minDistance: 0,
maxDistance: radiusinmetres,
spherical: true
}
},
{
$lookup:
{
from: 'collectionB',
pipeline: [
{ $match : { $and: [{ AttributeA :{$exists: true}}, { [category]: { $elemMatch: { name: “AttA_Name” } } }] }},
{ $project: { AttributeA: 0 } }
],
as: "collectionB_AttributeA"
}
}
])
If you can explain if this is possible or let me know off this is the right approach that would be helpful.
This is the query I've been using for getting some random uniqueXperiences, in that I've lookup xpert and I want to project its _id and name.
db.getCollection('uniquexperiences').aggregate([{
'$sample': {
'size': 2
}
}, {
'$lookup': {
'from': 'users',
'as': 'Xpert',
'pipeline':[{
'$project': {
'name': 1
}
}]
}
}]);
The output I'm getting is something like this:
/* 1 */
{
"_id" : ObjectId("5b558b5997199d3ec4953e6b"),
"updatedBy" : ObjectId("5b433dbf6a93e56a21f610eb"),
"updatedAt" : ISODate("2018-10-10T10:56:36.952Z"),
"createdBy" : ObjectId("5b433dbf6a93e56a21f610eb"),
"createdAt" : ISODate("2018-07-23T08:01:29.125Z"),
"title" : "Horse riding at EIRS",
"organisationFlag" : false,
"xperienceSubCategory" : [
ObjectId("5b4de8199f07bf0b303b8c5f")
],
"xpert" : [
ObjectId("5b51b054054a962cc6f914db")
],
"description" : "Beautiful rugged landscape makes Ladakh stand apart in the country. There is indeed so much that needs to be explored here and little did we know that amongst the best ways to explore this place is riding a horse. In the remote places like Zanskar Valley, where paved roads are rare and motor biking is not every ones cup of tea, horses make an incredible means of travel. One can access to Zangla, Penzela Pass, Panikhar Fort and Zongkhul, Stongdey and Gelugpa monasteries on a horseback.",
"__v" : 4,
"images" : [
{
"public_id" : "dotttg3xm0vvqygr4n1w",
"version" : 1537776979,
"signature" : "4fb562aa4115941e78f773dd11ed6be37a337acd",
"width" : 1280,
"height" : 640,
"format" : "jpg",
"resource_type" : "image",
"url" : "http://res.cloudinary.com/xplr-qa/image/upload/v1537776979/dotttg3xm0vvqygr4n1w.jpg",
"secure_url" : "https://res.cloudinary.com/xplr-qa/image/upload/v1537776979/dotttg3xm0vvqygr4n1w.jpg",
"_id" : ObjectId("5ba89d55ac69b4784a4f3a1f")
},
{
"public_id" : "cfdepst0r2wz39rowvzd",
"version" : 1537776980,
"signature" : "e770b7354c01ffce61c2e3cb83c79456dacc5438",
"width" : 2100,
"height" : 1526,
"format" : "jpg",
"resource_type" : "image",
"url" : "http://res.cloudinary.com/xplr-qa/image/upload/v1537776980/cfdepst0r2wz39rowvzd.jpg",
"secure_url" : "https://res.cloudinary.com/xplr-qa/image/upload/v1537776980/cfdepst0r2wz39rowvzd.jpg",
"_id" : ObjectId("5ba89d55ac69b4784a4f3a1e")
},
{
"public_id" : "lqfk6twitfefrjq1h2jq",
"version" : 1537776979,
"signature" : "ad1e0079a9419bde0047228446be17218117cf2e",
"width" : 2500,
"height" : 1666,
"format" : "jpg",
"resource_type" : "image",
"url" : "http://res.cloudinary.com/xplr-qa/image/upload/v1537776979/lqfk6twitfefrjq1h2jq.jpg",
"secure_url" : "https://res.cloudinary.com/xplr-qa/image/upload/v1537776979/lqfk6twitfefrjq1h2jq.jpg",
"_id" : ObjectId("5ba89d55ac69b4784a4f3a1d")
}
],
"source" : "",
"price" : 400,
"meetingLocation" : [],
"coordinates" : [
72.955162,
19.172098
],
"purchaseCount" : 10,
"Xpert" : [
{
"_id" : ObjectId("5b518101752982066a0dcc08"),
"name" : {
"last" : "Bourdain",
"first" : "Anthony"
}
},
{
"_id" : ObjectId("5b51b054054a962cc6f914db"),
"name" : {
"last" : "Yane",
"first" : "Sid"
}
},
{
"_id" : ObjectId("5b51c00597199d3ec4953e68"),
"name" : {
"last" : "ipsum",
"first" : "Lorem"
}
},
{
"_id" : ObjectId("5b59a8cdca722c3177cf3e63"),
"name" : {
"last" : "Lorem",
"first" : "Test"
}
},
{
"_id" : ObjectId("5b5eea6e2d4b6a04b2d9d599")
},
{
"_id" : ObjectId("5b5f02e22d4b6a04b2d9d5f1")
},
{
"_id" : ObjectId("5b60364f9e866d6453fef3ea"),
"name" : {
"last" : "Lorem",
"first" : "ipsum"
}
},
{
"_id" : ObjectId("5b6d70f96aaf19087ac6d9e9"),
"name" : {
"first" : "Indrajit",
"last" : "Jadhav"
}
},
{
"_id" : ObjectId("5b6d81953da5c50974642974"),
"name" : {
"last" : "Lorem",
"first" : "shin"
}
},
{
"_id" : ObjectId("5b6d831f3da5c50974642975"),
"name" : {
"last" : "Lorem",
"first" : "Shin "
}
},
{
"_id" : ObjectId("5b6d83b83da5c50974642976"),
"name" : {
"last" : "wert",
"first" : "fadsg"
}
},
{
"_id" : ObjectId("5b6d83ee3da5c50974642977"),
"name" : {
"last" : "asdfsaf",
"first" : "sadf"
}
},
{
"_id" : ObjectId("5b7ba46cd0e5fa137805552b"),
"name" : {
"first" : "Vivek",
"last" : "Pandey"
}
},
{
"_id" : ObjectId("5b7bb359d0e5fa13780555a9"),
"name" : {
"first" : "theamalageeks",
"last" : "null"
}
},
{
"_id" : ObjectId("5b7bd19ed0e5fa137805565d"),
"name" : {
"first" : "Anikesh",
"last" : "Baburanjan"
}
},
{
"_id" : ObjectId("5b7fa359211f5649518ae311"),
"name" : {
"first" : "Akhsay",
"last" : "Gaikwad"
}
},
{
"_id" : ObjectId("5b80181fab8747537011be5c"),
"name" : {
"first" : "Sagar",
"last" : "Bisen"
}
},
{
"_id" : ObjectId("5b83f1c5de663c0dcccfb483"),
"name" : {
"first" : "INDRAJIT",
"last" : "JADHAV"
}
},
{
"_id" : ObjectId("5b92154efc790f18121f9e02"),
"name" : {
"first" : "sagar",
"last" : "bisen"
}
},
{
"_id" : ObjectId("5ba39c509350135c9951ecb6"),
"name" : {
"first" : "Anikesh",
"last" : "Baburajan"
}
},
{
"_id" : ObjectId("5ba3b8e79350135c9951ecb7"),
"name" : {
"first" : "Anurag",
"last" : "Banerjee"
}
},
{
"_id" : ObjectId("5ba3c14e9350135c9951ecb8"),
"name" : {
"first" : "Dave",
"last" : "Jhala"
}
},
{
"_id" : ObjectId("5ba4dfcf6bb5277e1d7db2af"),
"name" : {
"first" : "Mark",
"last" : "Henry"
}
},
{
"_id" : ObjectId("5ba4e1c0452d7e01ce3dd34e"),
"name" : {
"first" : "Ankita",
"last" : "Mestry"
}
},
{
"_id" : ObjectId("5ba7795b452d7e01ce3dd34f"),
"name" : {
"first" : "Abhishek",
"last" : "Gupta"
}
},
{
"_id" : ObjectId("5ba9ec5844996a4be81a0c12"),
"name" : {
"first" : "Neeti",
"last" : "Patil"
}
},
{
"_id" : ObjectId("5baa1abf44996a4be81a0c13"),
"name" : {
"first" : "Krishna",
"last" : "S"
}
},
{
"_id" : ObjectId("5bb481d4c77dd914de2cb2f7"),
"name" : {
"first" : "krishna",
"last" : "shetty"
}
}
]
}
/* 2 */
{
"_id" : ObjectId("5bab23c897f85d07b9235a19"),
"updatedBy" : ObjectId("5b433dbf6a93e56a21f610eb"),
"updatedAt" : ISODate("2018-10-10T10:57:01.790Z"),
"createdBy" : ObjectId("5b433dbf6a93e56a21f610eb"),
"createdAt" : ISODate("2018-09-26T06:14:32.637Z"),
"xpert" : ObjectId("5ba4dfcf6bb5277e1d7db2af"),
"title" : "Mumbai Temples Tour",
"images" : [
{
"public_id" : "uvmemwfwmjfl7pmv4upk",
"version" : 1537943055,
"signature" : "5358320e4f396a2ee980e767a16d4a92228c95d6",
"width" : 1440,
"height" : 900,
"format" : "jpg",
"resource_type" : "image",
"url" : "http://res.cloudinary.com/xplr-qa/image/upload/v1537943055/uvmemwfwmjfl7pmv4upk.jpg",
"secure_url" : "https://res.cloudinary.com/xplr-qa/image/upload/v1537943055/uvmemwfwmjfl7pmv4upk.jpg",
"_id" : ObjectId("5bab260f97f85d07b9235a20")
},
{
"public_id" : "zztqwdbl7ejccxmougad",
"version" : 1537943055,
"signature" : "bcb413431d518b243d801f92ff9cf0a8f9bd7682",
"width" : 1920,
"height" : 1080,
"format" : "jpg",
"resource_type" : "image",
"url" : "http://res.cloudinary.com/xplr-qa/image/upload/v1537943055/zztqwdbl7ejccxmougad.jpg",
"secure_url" : "https://res.cloudinary.com/xplr-qa/image/upload/v1537943055/zztqwdbl7ejccxmougad.jpg",
"_id" : ObjectId("5bab260f97f85d07b9235a1f")
}
],
"organisationFlag" : false,
"xperienceSubCategory" : [
ObjectId("5b616b4c9e866d6453fef3eb")
],
"description" : "Global Vipassana Pagoda is an expression of our gratitude towards the Buddha who strived for incalculable aeons to reach Supreme Enlightenment.",
"__v" : 4,
"price" : 800,
"source" : "",
"meetingLocation" : [],
"coordinates" : [
72.955162,
19.172098
],
"primaryLocation" : ObjectId("5bacb0192e0b2751f0f7f057"),
"purchaseCount" : 20,
"Xpert" : [
{
"_id" : ObjectId("5b518101752982066a0dcc08"),
"name" : {
"last" : "Bourdain",
"first" : "Anthony"
}
},
{
"_id" : ObjectId("5b51b054054a962cc6f914db"),
"name" : {
"last" : "Yane",
"first" : "Sid"
}
},
{
"_id" : ObjectId("5b51c00597199d3ec4953e68"),
"name" : {
"last" : "ipsum",
"first" : "Lorem"
}
},
{
"_id" : ObjectId("5b59a8cdca722c3177cf3e63"),
"name" : {
"last" : "Lorem",
"first" : "Test"
}
},
{
"_id" : ObjectId("5b5eea6e2d4b6a04b2d9d599")
},
{
"_id" : ObjectId("5b5f02e22d4b6a04b2d9d5f1")
},
{
"_id" : ObjectId("5b60364f9e866d6453fef3ea"),
"name" : {
"last" : "Lorem",
"first" : "ipsum"
}
},
{
"_id" : ObjectId("5b6d70f96aaf19087ac6d9e9"),
"name" : {
"first" : "Indrajit",
"last" : "Jadhav"
}
},
{
"_id" : ObjectId("5b6d81953da5c50974642974"),
"name" : {
"last" : "Lorem",
"first" : "shin"
}
},
{
"_id" : ObjectId("5b6d831f3da5c50974642975"),
"name" : {
"last" : "Lorem",
"first" : "Shin "
}
},
{
"_id" : ObjectId("5b6d83b83da5c50974642976"),
"name" : {
"last" : "wert",
"first" : "fadsg"
}
},
{
"_id" : ObjectId("5b6d83ee3da5c50974642977"),
"name" : {
"last" : "asdfsaf",
"first" : "sadf"
}
},
{
"_id" : ObjectId("5b7ba46cd0e5fa137805552b"),
"name" : {
"first" : "Vivek",
"last" : "Pandey"
}
},
{
"_id" : ObjectId("5b7bb359d0e5fa13780555a9"),
"name" : {
"first" : "theamalageeks",
"last" : "null"
}
},
{
"_id" : ObjectId("5b7bd19ed0e5fa137805565d"),
"name" : {
"first" : "Anikesh",
"last" : "Baburanjan"
}
},
{
"_id" : ObjectId("5b7fa359211f5649518ae311"),
"name" : {
"first" : "Akhsay",
"last" : "Gaikwad"
}
},
{
"_id" : ObjectId("5b80181fab8747537011be5c"),
"name" : {
"first" : "Sagar",
"last" : "Bisen"
}
},
{
"_id" : ObjectId("5b83f1c5de663c0dcccfb483"),
"name" : {
"first" : "INDRAJIT",
"last" : "JADHAV"
}
},
{
"_id" : ObjectId("5b92154efc790f18121f9e02"),
"name" : {
"first" : "sagar",
"last" : "bisen"
}
},
{
"_id" : ObjectId("5ba39c509350135c9951ecb6"),
"name" : {
"first" : "Anikesh",
"last" : "Baburajan"
}
},
{
"_id" : ObjectId("5ba3b8e79350135c9951ecb7"),
"name" : {
"first" : "Anurag",
"last" : "Banerjee"
}
},
{
"_id" : ObjectId("5ba3c14e9350135c9951ecb8"),
"name" : {
"first" : "Dave",
"last" : "Jhala"
}
},
{
"_id" : ObjectId("5ba4dfcf6bb5277e1d7db2af"),
"name" : {
"first" : "Mark",
"last" : "Henry"
}
},
{
"_id" : ObjectId("5ba4e1c0452d7e01ce3dd34e"),
"name" : {
"first" : "Ankita",
"last" : "Mestry"
}
},
{
"_id" : ObjectId("5ba7795b452d7e01ce3dd34f"),
"name" : {
"first" : "Abhishek",
"last" : "Gupta"
}
},
{
"_id" : ObjectId("5ba9ec5844996a4be81a0c12"),
"name" : {
"first" : "Neeti",
"last" : "Patil"
}
},
{
"_id" : ObjectId("5baa1abf44996a4be81a0c13"),
"name" : {
"first" : "Krishna",
"last" : "S"
}
},
{
"_id" : ObjectId("5bb481d4c77dd914de2cb2f7"),
"name" : {
"first" : "krishna",
"last" : "shetty"
}
}
]
}
Instead of getting multiple Xperts in Xpert
Now I want to match the Xpert fields _id with xpert field of the output
Use the below aggregation.
Use $lookup pipeline variant. Let expression checks for a array type for xpert and converts into array when it is not. $match to collect all the matching users documents. $project to output name from user document.
db.uniquexperiences.aggregate([
{"$sample":{"size":2}},
{"$lookup":{
"from":"users",
"let":{"xpert":{"$cond":[{"$isArray":"$xpert"},"$xpert",["$xpert"]]}},
"pipeline":[
{"$match":{"$expr":{"$in":["$_id","$$xpert"]}}},
{"$project":{"name":1}}],
"as":"Xpert"
}}
])
i have inside my mongoDB collection this document
{
"_id" : ObjectId("5b633025579fac22e74bf3be"),
"FLAGS" : [
{
"toSent" : [
{
"_id" : ObjectId("5b633025579fac22e74bf3c2"),
"phone" : "+84404040404"
},
{
"_id" : ObjectId("5b633025579fac22e74bf3c1"),
"phone" : "+212652253403"
},
{
"_id" : ObjectId("5b633025579fac22e74bf3c0"),
"phone" : "+212123456788"
}
],
"_id" : ObjectId("5b633025579fac22e74bf3bf"),
"action" : "group_p_a"
},
{
"toSent" : [
{
"_id" : ObjectId("5b633031579fac22e74bf3c9"),
"phone" : "+212651077199"
},
{
"_id" : ObjectId("5b633031579fac22e74bf3c8"),
"phone" : "+84404040404"
},
{
"_id" : ObjectId("5b633031579fac22e74bf3c7"),
"phone" : "+212652253403"
},
{
"_id" : ObjectId("5b633031579fac22e74bf3c6"),
"phone" : "+212123456788"
}
],
"_id" : ObjectId("5b633031579fac22e74bf3c5"),
"action" : "group_p_a"
}
],
"time" : ISODate("2018-08-02T16:24:05.747+0000"),
"action_user_phone" : "+212123456788",
"idGroup" : "e534379a-1580-4568-b5ec-6eaf981538d2",
"nomGroup" : "MOH FOR EVER",
"__v" : NumberInt(0)
}
TODO
I need to remove for example this element { "_id" : ObjectId("5b633025579fac22e74bf3c2"), "phone" : "+84404040404"}
WHAT I DID
GroupEvents.update({}, {$pull:{FLAGS:{$elemMatch:{toSent:{phone: "+84404040404"} }}}},function(err,ret){
if(err)
console.log("error"+err);
if(ret)
console.log(ret);
});
It remove all what's inside toSent event if it doesn't match.
Any help please
You need to use $ positional operator instead of $elemMatch here
GroupEvents.update(
{ "Flags.toSent.phone": "+84404040404" },
{ "$pull": { "FLAGS.$.toSent": { "phone": "+84404040404" }}},
)
If you want remove from every element of FLAGS array this you need to use $[] the all positional operator
GroupEvents.update(
{ "Flags.toSent.phone": "+84404040404" },
{ "$pull": { "FLAGS.$[].toSent": { "phone": "+84404040404" }}},
)
Can anyone help I am using $lookup for join in MongoDB to get all orders where the date is between date "X" and date "Y" and chef_id is "P". something is wrong in "date" part which is not giving data on the dates. but when I use it in single Find query it works fine and gives data between the dates. but it does not give data when I applied with $lookup for join.
Here is my query
Order.aggregate([{
"$lookup": {
"localField": "user_id",
"from": "users",
"foreignField": "_id",
"as": "order_data"
}
},
{
"$match": {
"$and": [
{ "chef_id": mongoose.Types.ObjectId(req.body.chef_id) },
{ "booking_datetime": { $gte: start_time,
$lte: end_time } }
]
}
}
], function(err, gettt) {
if (err) {
res.json({ 'message': "Error", 'status': false, 'data': err });
return false;
} else {
if (gettt.length != 0) {
res.json({ 'message': "Orders Data", 'status': true, 'data': gettt });
} else {
res.json({ 'message': "No Orders for this date", 'status': false, 'data': gettt });
}
}
});
Can anyone help me out.
my collection is here "Order" collection
{
"_id" : ObjectId("5a4256cc3f76bc45065021fc"),
"order_status" : 2,
"total_order_amount" : "160",
"booking_datetime" : ISODate("2017-12-29T23:24:00.000Z"),
"customer_address" : "121/161, South Extension part",
"user_id" : ObjectId("5a3cb4a8a188f2074714f1de"),
"chef_id" : ObjectId("5a390b07f0b3563db59cb3ca"),
"updated_at" : ISODate("2017-12-26T14:03:56.742Z"),
"created_at" : ISODate("2017-12-26T14:03:56.342Z"),
"products" : [
{
"product_id" : "5a3a50fcefc0c972377c3012",
"product_name" : "sweet corn",
"quantity" : "12",
"_id" : ObjectId("5a4256cc3f76bc45065021fd"),
"updated_at" : ISODate("2017-12-26T14:03:56.736Z"),
"created_at" : ISODate("2017-12-26T14:03:56.736Z")
},
{
"product_id" : "5a3a5119efc0c972377c3013",
"product_name" : "chilly paneer",
"quantity" : "10",
"_id" : ObjectId("5a4256cc3f76bc45065021fe"),
"updated_at" : ISODate("2017-12-26T14:03:56.736Z"),
"created_at" : ISODate("2017-12-26T14:03:56.736Z")
},
{
"product_id" : "5a3a512cefc0c972377c3014",
"product_name" : "Gulab jamun",
"quantity" : "20",
"_id" : ObjectId("5a4256cc3f76bc45065021ff"),
"updated_at" : ISODate("2017-12-26T14:03:56.736Z"),
"created_at" : ISODate("2017-12-26T14:03:56.736Z")
},
{
"product_id" : "5a3a50fcefc0c972377c3012",
"product_name" : "ali baba",
"quantity" : "56",
"_id" : ObjectId("5a4256cc3f76bc4506502200"),
"updated_at" : ISODate("2017-12-26T14:03:56.736Z"),
"created_at" : ISODate("2017-12-26T14:03:56.736Z")
}
],
"__v" : 1
and here is my User Collection
{
"_id" : ObjectId("5a623f67eaa08537fe0dba02"),
"salt" : "73824ba53291740e15d26c300c997ce1436ac678299101171af74f4980433285",
"hash" : "8f78291ac737dac15f59f5438033a61de75282a3c671a8d0231406a8374adec140b4cb2dd30b852f05241c6f9900443906fafec22ad58c983dacaed8f9ef4f9039e72b748d9c63d924239aa40372923d824a9cc796079556c8bc5eb0b0f6b17e7fd4c35b8780c870d1b4b819e641e56ce2f88fb0a7fdfbfd91d15921e9b7441a7051523903b43b930f56057852e41ffdbdc044cc09b14ebaac77940576b483d58ff1e18c381d40a143abcd1a180ca208aac6a13eb5c819b97e7e5753bd6fc40fcc1e19b55cb816879b3fedbf187110e84149bad0918672bd2de49bc323a32f04dd0e55aded9a0157fd5eea7db645303eb4cf461e47ca905e1f196618814b88421a3cab9463dac01d5bf6aebcace6e4b1215c3cf07aaae1cac07c94dc28432d223407778f4c6b12b089e09d56a59b1f00084c727f06247c1799c1a8616c74693e2d7057a5026e3c02b9ef73bf867873508575a33fc1e956bd3c704c54e6cc38ffb22e7a04ade70db134ec87e9ed3f43a7273db115127470f8ca5d8def49ba47fe7852cdf0cbd3140b19d5fe358d29eb84519365eea6353fa34c7a6757fbd9ec2ba93eca802f21944da58cd72b5d0d7000f9fd6f231f0668b7e621117a18fcedf977515e181325a9210380e01892891fcc420a67cb5246688eb6e577fccb6d41e719b426fa20c4689af9a9485d0ae0cf026845de8b4f12c7277b9cc506b5e29224",
"email" : "eduardo.llano#geocampo.co",
"firstname" : "Pedro",
"lastname" : "Peez",
"dob" : "1980-01-19",
"phone" : "3185311158",
"gender" : "male",
"latitude" : "4.6936225",
"longitude" : "-74.0730777",
"address" : "Bogota",
"divice_token" : "dcd8cf3ceefc39b8",
"prossing_form" : "1",
"status" : true,
"role" : "chef",
"updated_at" : ISODate("2018-02-01T16:09:27.465Z"),
"created_at" : ISODate("2018-01-19T18:56:39.070Z"),
"products" : [
{
"product_name" : "Producto 1",
"product_price" : "100",
"discount" : "10",
"product_ingredients" : "Pepper",
"product_description" : "Nsjdjd jsjdjdjx",
"minimum_order" : "2",
"tags" : "Indian food",
"status" : "1",
"product_image0" : "https://s3-us-west-2.amazonaws.com/rafahoproject/a47df980-7221-4fde-97cd-977cb3dd1dcf.jpg",
"product_image1" : "https://s3-us-west-2.amazonaws.com/rafahoproject/3a282cae-028c-4d4a-9a22-4c2c43d440f1.jpg",
"product_image2" : "https://s3-us-west-2.amazonaws.com/rafahoproject/1ab4373e-ec63-43fe-9b94-7b85d289c7f9.jpg",
"_id" : ObjectId("5a6602aa135fae732d5ce3d7")
},
{
"product_name" : "Bandeja Paisa",
"product_price" : 100,
"discount" : 20,
"cuisine" : "Continental",
"minimum_order" : 5,
"cooking_time_at_chef_place" : 8,
"cooking_time_at_user_home" : 10,
"tags" : "Bandeja-Paisa,Bandeja,Paisa",
"status" : "1",
"product_image0" : "https://s3-us-west-2.amazonaws.com/rafahoproject/0252161e-0e2a-4682-b7ab-0dce355be794.jpg",
"_id" : ObjectId("5a71d268947536411def9b11")
},
{
"product_name" : "Fritanga",
"product_price" : 200,
"discount" : 30,
"cuisine" : "continental",
"minimum_order" : 6,
"cooking_time_at_chef_place" : 3,
"cooking_time_at_user_home" : 5,
"tags" : "Fritanga,platter-of-grilled-meats",
"status" : "1",
"product_image0" : "https://s3-us-west-2.amazonaws.com/rafahoproject/14c39e2f-4d02-4cd1-8aa7-2f7179b5ea0c.jpg",
"_id" : ObjectId("5a71d3c6947536411def9b12")
},
{
"product_name" : "Dominican Sancocho",
"product_price" : 300,
"discount" : 50,
"cuisine" : "continental",
"minimum_order" : 5,
"cooking_time_at_chef_place" : 1,
"cooking_time_at_user_home" : 2,
"tags" : "Dominican-Sancocho,Dominican,Sancocho",
"status" : "1",
"product_image0" : "https://s3-us-west-2.amazonaws.com/rafahoproject/40a701ff-f868-492d-bee1-d65004fff024.jpg",
"_id" : ObjectId("5a71d4da947536411def9b13")
},
{
"product_name" : "Sudado de Pollo",
"product_price" : 60,
"discount" : 10,
"cuisine" : "Continental",
"minimum_order" : 3,
"cooking_time_at_chef_place" : 3,
"cooking_time_at_user_home" : 2,
"tags" : "Sudado-de-Pollo,Sudado,de-Pollo",
"status" : "1",
"product_image0" : "https://s3-us-west-2.amazonaws.com/rafahoproject/544c2ceb-839b-4263-b482-e2262c228948.jpg",
"_id" : ObjectId("5a71d6e9947536411def9b14")
}
],
"loc" : {
"coordinates" : [
-74.0730777,
4.6936225
],
"type" : "Point"
},
"__v" : 9,
}
Your syntax looks good. I still suspect there is some data type mismatch or erroneous format. I have a similar aggregate which matches a date range, and I use new Date() to convert my strings to date.
if (typeof dateBeginning === "string" && dateBeginning != "" && typeof dateEnding === "string" && dateEnding != "" && dateEnding >= dateBeginning) {
query.date = { $gte: new Date(dateBeginning), $lte: new Date(dateEnding) };
}
Here is an SO question: Date query with ISODate in mongodb doesn't seem to work
which was resolved this way.
Also, Veeram is correct; you should put your $match first. That way, MongoDb will use any indexes on the match fields that are available.
I am trying to use $geoNear aggregation operator of mongoDb to calculate distances of users from current location in following way :
'$geoNear': {
near: currentLocation,
distanceField: 'distance',
spherical: true,
}
With currentLocation being something like:
{ "type" : "Point", "coordinates" : [ -122.1575745, 37.4457966 ] }
My collection is of following type (using mongoose):
users = [{
....
location : { // GeoJSON Point or I think it is ;)
type: {
type: String
},
coordinates: []
}
....
}]
I am using index (again mongoose's syntax):
userSchema.index({
location: '2dsphere'
});
Now the PROBLEM I am facing is that, if I query using currentLocation as mentioned above (in form of GeoJSON) I get weird distances (very huge numbers), but if I use currentLocation.coordinates, i.e using legacy coordinate pairs ([-122.1575745, 37.4457966]), I get correct result. But mongoDb docs for geoNear clearly says that we can query using both GeoJSON point or legacy coordinate pairs.
I am curious to know what exactly is difference between GeoJSON point and legacy coordinate pairs ?
E.g Collection:
{ "_id" : ObjectId("5277679914c6d8f00b000003"), "location" : { "type" : "Point", "coordinates" : [ 106.6202887, -6.1293536 ] } }
{ "_id" : ObjectId("5277810148219d011c000003"), "location" : { "type" : "Point", "coordinates" : [ 106.6202887, -6.1293536 ] } }
{ "_id" : ObjectId("5281c7ba2dfd7bdc64000003"), "location" : { "type" : "Point", "coordinates" : [ -86.9248483, 33.4480108 ] } }
{ "_id" : ObjectId("5281c8b82dfd7bdc64000004"), "location" : { "type" : "Point", "coordinates" : [ -74.0087126, 40.7136487 ] } }
{ "_id" : ObjectId("5281c9782dfd7bdc64000005"), "location" : { "type" : "Point", "coordinates" : [ -122.1575745, 37.4457966 ] } }
Incorrect result:
[{"location":{"type":"Point","coordinates":[-122.1575745,37.4457966]},"dis":13.69288259318155},
{"location":{"type":"Point","coordinates":[-86.9248483,33.4480108]},"dis":12697164592.388557},
{"location":{"type":"Point","coordinates":[-74.0087126,40.7136487]},"dis":16328789117.58145},
{"location":{"type":"Point","coordinates":[106.6202887,-6.1293536]},"dis":55446284682.14049},
{"location":{"type":"Point","coordinates":[106.6202887,-6.1293536]},"dis":55446284682.14049}]
Lets create some example documents and geospatial index:
> db.foo.insert({name: "Warsaw", location: {"type" : "Point", "coordinates" : [21.016667, 52.233333]}})
> db.foo.insert({name: "Stockholm", location: {"type" : "Point", "coordinates" : [18.068611, 59.329444]}})
> db.foo.ensureIndex({"location": "2dsphere"})
Distance between Warsaw PL and and Stockholm SE is somewhere about 810 km so let's check if it works as expected. First we can fetch document for Stockholm.
> Stockholm = db.foo.findOne({name: "Stockholm"})
Now we can run query using geoNear:
> db.runCommand({ geoNear: 'foo', near: Stockholm.location.coordinates, spherical: true })
{
"ns" : "test.foo",
"results" : [
{
"dis" : 6.558558954334308e-10,
"obj" : {
"_id" : ObjectId("52876ab0b12c6fc62f5d9311"),
"name" : "Stockholm",
"location" : {
"type" : "Point",
"coordinates" : [
18.068611,
59.329444
]
}
}
},
{
"dis" : 0.12715355275490586,
"obj" : {
"_id" : ObjectId("5287697eb12c6fc62f5d9310"),
"name" : "Warsaw",
"location" : {
"type" : "Point",
"coordinates" : [
21.016667,
52.233333
]
}
}
}
],
"stats" : {
"time" : 9,
"nscanned" : 3,
"avgDistance" : 0.06357677670538088,
"maxDistance" : 0.12715355275490586
},
"ok" : 1
}
Distance between Stockholm ans Stockholm is close to 0 as expected. Distance between Stockholm and Warsaw is 0.12715355275490586. When you run query using legacy coordinate pairs you get result in radians so we have to multiply this value by Earth radius:
> 0.12715355275490586 * 6371.0
810.0952846015052
So far so good. Lets check if we get similar result using geojson as a query.
> db.runCommand({ geoNear: 'foo', near: Stockholm.location, spherical: true })
{
"ns" : "test.foo",
"results" : [
{
"dis" : 0.004183114486663965,
"obj" : {
"_id" : ObjectId("52876ab0b12c6fc62f5d9311"),
"name" : "Stockholm",
"location" : {
"type" : "Point",
"coordinates" : [
18.068611,
59.329444
]
}
}
},
{
"dis" : 810998.0748260651,
"obj" : {
"_id" : ObjectId("5287697eb12c6fc62f5d9310"),
"name" : "Warsaw",
"location" : {
"type" : "Point",
"coordinates" : [
21.016667,
52.233333
]
}
}
}
],
"stats" : {
"time" : 4,
"nscanned" : 3,
"avgDistance" : 405499.0395045898,
"maxDistance" : 810998.0748260651
},
"ok" : 1
}
Distance between Stockholm ans Stockholm is once again close to 0. Distance between Stockholm and Warsaw is 810998.0748260651. When you run geoNear query using GeoJSON distances are calculated in meters. 810998.0748260651 is roughly equal to 810 km so nothing strange here.
> 810998.0748260651 / 1000
810.9980748260651
Difference between both solutions could be smaller but it is just a FP arithmetics.
> Math.abs(810.0952846015052 - 810.9980748260651)
0.902790224559908
When you use find command with $near operator. When you create simple 2d index on legacy coordinates pairs it can be queried using both {$near: Stockholm.location.coordinates} and {$near: {$geometry: Stockholm.location}. If you have 2dsperhical only {$near: {$geometry: Stockholm.location} will work.