$geoIntersects returns no results - mongodb

I am querying a polygon, to check if a point is inside of it or not, but no results are returned. I am in the mongo shell: (MongoDB shell version: 3.2.6)
db.restPolygons.find();
{
"_id" : ObjectId("586e663175c32828be59e3a9"),
"zoneCoordinates" : {
"type" : "Polygon",
"coordinates" : [
[ 2, 0 ],
[ 6, 0 ],
[ 6, 2 ],
[ 2, 2 ],
[ 2, 0 ]
]
}
}
db.restPolygons.find({
"zoneCoordinates": {
"$geoIntersects": {
"$geometry": {
"type": "Point",
"coordinates": [3 ,1]
}
}
}
}).count();
0

Your polygon is invalid, it's missing a level of enclosing array in the coordinates field. This one should work:
> db.geo.find()
{
"_id": ObjectId("586e663175c32828be59e3a9"),
"zoneCoordinates": {
"type": "Polygon",
"coordinates": [
[
[2, 0],
[6, 0],
[6, 2],
[2, 2],
[2, 0]
]
]
}
}
> db.geo.find({
"zoneCoordinates": {
"$geoIntersects": {
"$geometry": {
"type": "Point",
"coordinates": [3 ,1]
}
}
}
}).count()
1
You can check the validity of your GeoJSON object in GeoJSONLint

Related

JOLT prefix soup example with an array of objects as input

I am looking at the prefix soup example from jolt-demo.appspot, which seems to be almost exactly what I need however I made a minor modification on the input to have multiple objects in an array, then I changed the spec to have * wildcard to account for the array and the result is not exactly how I need it. I'm obviously missing something fundamental but I don't know what. Any help would be greatly appreciated.
Input JSON
[
{
"rating-primary": 1,
"rating-Price": 2,
"rating-Design": 4,
"rating-RatingDimension3": 1
},
{
"rating-primary": 7,
"rating-Price": 8,
"rating-Design": 9,
"rating-RatingDimension3": 10
}
]
Spec
[
{
"operation": "shift",
"spec": {
"*": {
"rating-primary": "Rating",
"rating-*": "SecondaryRatings.&(0,1)"
}
}
}
]
Expected Output
[
{
"Rating": 1,
"SecondaryRatings": {
"Primary": 1,
"Price": 2,
"Design": 4,
"RatingDimension3": 1
}
},
{
"Rating": 7,
"SecondaryRatings": {
"Primary": 1,
"Price": 2,
"Design": 4,
"RatingDimension3": 1
}
}
]
Actual Output
{
"Rating" : [ 1, 7 ],
"SecondaryRatings" : {
"Price" : [ 2, 8 ],
"Design" : [ 4, 9 ],
"RatingDimension3" : [ 1, 10 ]
}
}
I figured it out. Here is the spec in case anyone else needs it.
[
{
"operation": "shift",
"spec": {
"*": {
"rating-*": "[&1].SecondaryRatings.&(0,1)",
"rating-primary": "[&1].Rating"
}
}
}
]
'''

Create array if not exists or append item to existing

I need to add items to a specific subobject in my collection. Is is possible to do this using just the update method considering that the array may not exist in some objects?
Here's a sample structure:
[
{
"key": 1,
"someValue": "abc",
"installments": [
{
"number": 1,
"payments": [
{
"paymentNumber": 1,
"value": 29
},
{
"paymentNumber": 2,
"value": 22
}
]
}
]
},
{
"key": 2,
"someValue": "xyz",
"installments": [
{
"number": 1,
"payments": [
{
"paymentNumber": 3,
"value": 10
},
{
"paymentNumber": 4,
"value": 1
},
{
"paymentNumber": 5,
"value": 5
}
]
}
]
}
]
And here's the syntax I'm using:
db.collection.update({
"installments.payments.paymentNumber": 4
},
{
"$push": {
"installments.payments": [
{
"receipts": [
{
"receiptNumber": 1
}
]
}
]
}
})
This is causing this error:
fail to run update: multiple write errors: [{write errors: [{Cannot create field 'payments' in element {installments: [ { number: 1.0, payments: [ { paymentNumber: 3.0, value: 10.0 }, { paymentNumber: 4.0, value: 1.0 }, { paymentNumber: 5.0, value: 5.0 } ] } ]}}]}, {<nil>}]
Is it possible?
Here's the Mongo Playground link
And here's the expected result:
[
{
"key": 1,
"someValue": "abc",
"installments": [
{
"number": 1,
"payments": [
{
"paymentNumber": 1,
"value": 29
},
{
"paymentNumber": 2,
"value": 22
}
]
}
]
},
{
"key": 2,
"someValue": "xyz",
"installments": [
{
"number": 1,
"payments": [
{
"paymentNumber": 3,
"value": 10
},
{
"paymentNumber": 4,
"value": 1,
"receipts": [{
"receiptNumber": 1
}]
},
{
"paymentNumber": 5,
"value": 5
}
]
}
]
}
]
To update nested arrays, the filtered positional operator $[identifier] identifies the array elements that match the arrayFilters conditions for an update operation.
Try the following query to $push in nested array:
db.collection.update({
"installments.payments.paymentNumber": 4,
},
{
"$push": {
"installments.$.payments.$[payments].receipts": {
"receiptNumber": 1
}
}
},
{
"arrayFilters": [
{
"payments.paymentNumber": 4
}
],
multi: true
})
MongoDB Playground

How to multi update of a nested array in MondoDB?

I have documents in a MongoDB 'playground' collection following the below "schema" :
{
"_id": ObjectId("54423b40c92f9fffb486a6d4"),
"ProjectFileId": 1,
"SourceLanguageId": 2,
"TargetSegments": [
{
"LanguageId": 1,
"Segment": "Something",
"Colors": [
1,
2,
3
],
"Heights": [
1,
2,
3
],
"Widths": [
1,
2,
3
]
},
{
"LanguageId": 1,
"Segment": "Something",
"Colors": [
1,
2,
3
],
"Heights": [
1,
2,
3
],
"Widths": [
1,
2,
3
]
}
]
}
And the following update query:
db.playground.update({
$and: [
{
"TargetSegments.Colors": {
$exists: true
}
},
{
"ProjectFileId": 1
},
{
"SourceLanguageId": 2
},
{
"TargetSegments": {
$elemMatch: {
"LanguageId": 1
}
}
}
]
},
{
$set: {
"TargetSegments.$.Segment": null,
"TargetSegments.$.Colors": [],
"TargetSegments.$.Widths": [],
"TargetSegments.$.Heights": []
}
},
false, true)
After the execution of the query the result is:
{
"_id": ObjectId("54423b40c92f9fffb486a6d4"),
"ProjectFileId": 1,
"SourceLanguageId": 2,
"TargetSegments": [
{
"LanguageId": 1,
"Segment": null,
"Colors": [],
"Heights": [],
"Widths": []
},
{
"LanguageId": 1,
"Segment": "Something",
"Colors": [
1,
2,
3
],
"Heights": [
1,
2,
3
],
"Widths": [
1,
2,
3
]
}
]
}
As you can see, only the first element of the "TargetSegments" array is updated.
How can I update all the elements of the TargetSegments array in one update query?
Its because you are using $ operator: The positional $ operator identifies an element (not multi) in an array to update without explicitly specifying the position of the element in the array. To project, or return, an array element from a read operation, see the $ projection operator.
You can use below code to do it:
db.playground.find({
$and: [
{
"TargetSegments.Colors": {
$exists: true
}
},
{
"ProjectFileId": 1
},
{
"SourceLanguageId": 2
},
{
"TargetSegments": {
$elemMatch: {
"LanguageId": 1
}
}
}
]
}).forEach(function(item)
{
var targets = item.TargetSegments;
for(var index = 0; index < targets.length; index++)
{
var target = targets[index];
target.Segment = null,
target.Colors= [],
target.Widths= [],
target.Heights= []
}
db.playground.save(item);
});

$geoIntersects don't work like expected

I have a question to the $geoIntersects-Operator.
I have the following searchBox and collection-content:
> BOX
{
"type" : "Polygon",
"coordinates" : [
[
[
0,
0
],
[
3,
0
],
[
3,
3
],
[
0,
3
],
[
0,
0
]
]
]
}
> db.polygon.find()
{ "_id" : "Poly1", "shape" : { "type" : "Polygon", "coordinates" : [ [ [ 0, 0 ], [ 3, 0 ], [ 3, 3 ], [ 0, 3 ], [ 0, 0 ] ] ] } }
{ "_id" : "Poly2", "shape" : { "type" : "Polygon", "coordinates" : [ [ [ 3, 0 ], [ 6, 0 ], [ 6, 3 ], [ 3, 3 ], [ 3, 0 ] ] ] } }
> db.polygon.find( {shape: {$geoIntersects: {$geometry: BOX}}}, {_id:1})
{ "_id" : "Poly1" }
Like you can see, the BOX and Poly1 are identical.
Poly2 shared an edge with BOX.
So when I was executing the $geoIntersects-Query I was expecting that both polygon’s where returned because of the shared edge, but only Poly1 was found.
Can somebody explain that to me? Or did I made a stupid mistake I don’t see :(
Auf Wiedersehen, Andre
Good question. It looks like it's a bug or the documentation is not accurate. Just want to share the results of my small research on the issue
Point:
.find( {shape: {$geoIntersects: {$geometry: {type: "Point", coordinates : [3,0] }}}}, {_id:1})
No surprise it returns both Poly1 and Poly2.
LineString:
.find( {shape: {$geoIntersects: {$geometry: {type: "LineString", coordinates : [[3,0], [3, 3]] }}}}, {_id:1})
Returns Poly1 only, what if we revert the order of line points?
.find( {shape: {$geoIntersects: {$geometry: {type: "LineString", coordinates : [[3,3], [3, 0]] }}}}, {_id:1})
Returns Poly2 only now. So the order of the points is important for LineString which is really weird to me.
Polygon:
Let's also try to change the order of points for polygon query.
.find( {shape: {$geoIntersects: {$geometry: {type: "Polygon", coordinates : [ [ [ 3, 0 ], [ 3, 3 ], [ 6, 3 ], [ 6, 0 ], [ 3, 0 ] ] ]}}
Now even the order of points for line [ 3, 0 ], [ 3, 3 ] matches Poly1 definition but it still returns Poly2 only.
Summary:
So when the documentation says that
This includes documents that have a shared edge
It's no surprise true for Point, it is partially true for LineString because the order of points is important! Finnaly it's not true at all for Polygon.
This is sad in fact but really good to know. I wish I were doing something wrong during my research and would be glad if someone drop in with a good explanation.
just use smaller numbers. for triangles like these:
[{
_id:54cfbc19d9e1f418373ee427,
geo:{type:Polygon,
coordinates:[[[0.3,0.3],[0,0.3],[0,0],[0.3,0.3]]]}
},
{_id:54cfbc19d9e1f418373ee428,
geo:{type:Polygon,
coordinates:[[[0,0],[0.3,0],[0.3,0.3],[0,0]]]}
}]
.find({
geo: {
$geoIntersects: {
$geometry: {
type: "Point" ,
coordinates: [0.005,0.005]
}
}
}
})
will give you right result.
I guess that $geoIntersects count that Earth is sphere.

MongoDB: How to use property in find query?

I have user collection:
{
"_id": { "$oid" : "514C438232F5699004000014" },
"gender": 1,
"loc": {
"coordinates": [
0.777084,
0.701690
],
"type": "Point"
},
"name": "H1",
"radius": 1
},
{
"_id": { "$oid" : "514C438232F5699004000014" },
"gender": 1,
"loc": {
"coordinates": [
0.677084,
0.701690
],
"type": "Point"
},
"name": "H2",
"radius": 0.4
}
db.user.ensureIndex( { loc : "2dsphere" } )
I need to write query and use radius property from collection's row ( "radius": 1 ) in find query like this:
db.user.find( { loc: { $geoWithin :{ $centerSphere : [ [0.7, 0.7 ] , radius ]} } } )
But mongo returns:
JavaScript execution failed: ReferenceError: radius is not defined
I have tried db.user.find( { loc: { $geoWithin :{ $centerSphere : [ [0.7, 0.7 ] , this.radius ]} } } )
I think you have to do a two way query. First fetch the radius of a given user, then search for all location within this radius.