everyone. Hope you are doing well. I currently have this problem.
This is my 'Travel' Schema.
const TravelSchema = new mongoose.Schema({
...
route: [{
index: { type: Number},
lat: { type: Number },
lng: { type: Number },
}],
...
});
This is where I handled post request. (Save new Travel)
...
const {route, ...rest} = req.body;
const newTravel = new Travel({
route: route.map((location, index) => ({index, ...location})),
...rest
});
const Travel = await newTravel.save();
...
Search by start and end locations in order. tart and end locations are objects with 'lat' and 'lng' properties.
...
const { start, end } = req.body;
//start -> {lat: 51.11213, lng: 19.1239219} //for example
const travels = await Travel.find({
route: { $all: [ {$elemMatch: {...start}}, {$elemMatch: {...end}} ] },
$expr: {
$lt: [
{$arrayElemAt: ['$route.index', {$indexOfArray: ['$route', {...start}]}]},
{$arrayElemAt: [{$reverseArray: '$route.index'}, {$indexOfArray: [{$reverseArray: '$route'}, {...end}]}]},
]
}
});
console.log(travels); // [] is printed
...
Without $expr, I can get some results but not accurate ones. What I want exactly is like this:
route: [{index: 0, lat: 54, lng: 13}, //same as end but not considered regarding order
{index: 1, lat: 32, lng: 51},
{index: 1, lat: 10, lng: 30}, //start
{index: 2, lat: 54, lng: 13}] //end
start: {lat: 10, lng: 30}, end: {lat: 54, lng: 13}
the route is filtered
route: [{index: 0, lat: 54, lng: 13}, //end
{index: 1, lat: 32, lng: 51},
{index: 1, lat: 10, lng: 30}] //start
start: {lat: 10, lng: 30}, end: {lat: 54, lng: 13}
the route is not filtered this time
Would you please help me to fix this issue? Thanks in advance.
CodePudding user response:
If I understand correctly, you can use $min
and $max
with $reduce
.
Since $indexOfArray
returns the index of the first occurrence, it should not be used here, as you may have the same corrdinated multiple times. Using $reduce
can create an array of all relevant indices for the start point and for the end point. Using $min
and $max
allows to check if there is a start point index that is smaller than an end-point index:
db.collection.find({
route: {$all: [ {$elemMatch: {...start}}, {$elemMatch: {...end}} ] },
$expr: {$lt: [
{$min: {
$reduce: {
input: "$route",
initialValue: [],
in: {
$cond: [
{$and: [{$eq: ["$$this.lat", start.lat]}, {$eq: ["$$this.lng", start.lng]}]},
{$concatArrays: ["$$value", ["$$this.index"]]},
"$$value"
]
}
}
}},
{$max: {
$reduce: {
input: "$route",
initialValue: [],
in: {
$cond: [
{$and: [{$eq: ["$$this.lat", end.lat]}, {$eq: ["$$this.lng", end.lng]}]},
{$concatArrays: ["$$value", ["$$this.index"]]},
"$$value"
]
}
}
}}
]
}
})
See how it works on the playground example