How to use geoNear in pipeline

Hello, I try to use the geoNear in pipeline, the code as below:

func countPlaceNear(db *mongo.Database, lng float64, lat float64) error {
pipeline := []bson.M{
		bson.M{
			"$geoNear": []bson.M{
				bson.M{"includeLocs": "location"},
				bson.M{"distanceField": "distance"},
				bson.M{"near": []bson.M{bson.M{"type": "Point"}, bson.M{"coordinates": []float64{lat, lng}}}},
				bson.M{"maxDistance": 1000},
				bson.M{"spherical": true},
			},
		},
		bson.M{
			"$count": "number",
		},
}
cur, err := db.Collection("place").Aggregate(context.TODO(), pipeline, options.Aggregate())

I get the error: (Location16605) $geoNear requires a ‘near’ option as an Array.
then I change the line to:

bson.M{"near": []float64{lat, lng}},

the same error.

any help?

James

Hi James,

The argument for $geoNear should be a single BSON document, not a slice of BSON documents. See https://docs.mongodb.com/manual/reference/operator/aggregation/geoNear/ for some examples. For your pipeline specifically, I think it can be written as the following:

pipeline := []bson.M{
	bson.M{
		"$geoNear": bson.M{
			"includeLocs":   "location",
			"distanceField": "distance",
			"maxDistance":   1000,
			"spherical":     true,
			"near": bson.M{
				"type":        "Point",
				"coordinates": []float64{lat, long},
			},
		},
	},
	bson.M{
		"$count": "number",
	},
}

Can you see if this works for you?

– Divjot

Hello Divjot,

Thank you for you answer. It is not so straightforward to write the pipeline in this way. I found at github.com/mongodb/mongo-go-driver/bson there is a function bson.ParseExtJSONArray, which can turn the json string directly to be a pipeline. It is not in the official library go.mongodb.org/mongo-driver/bson, can I use it in my project?

Thanks,

James

Can you explain why it’s not straightforward to write this pipeline? It seems simpler than the original pipeline you had in your question. Also, there is no bson.ParseExtJSONArray function in the current driver. Perhaps you’re looking at a very old version of the driver? Can you send a link to the source code for this function on Github?

Hello Divjot,

Many thanks for the answer. For me it is not straightforward, because It is hard to find good examples to write the pipeline correctly, and if there are errors, the error message print out are not clear enough to let me fix the issue. Personally, I think here the its better to say: near should be a bson.M object. The second issue: I will try the pipeline from the mongo cli client, but the pipeline text can’t be used directly in the golang code, we have to make it as bson manually(please tell me there are other tool to help if I am wrong). So here the better way for me, and for other developers reviewing the code, is to use json string build the pipeline. Except the geoNear operators, I have other questions related to how to write pipeline to “search text”, like bson.M{"$text": bson.M{"$search": in.Term}}, and how to write pipeline to match (an objectID and a bool value), when there are nested operator and parameters, I will feel confused…

Regards,

James

and as to the bson.ParseExtJSONArray, is there other equivalent functions can do the job? My purpose is simple: I will write and test the json in mongo cli, then use this function to translate it to bson objects and used in golang code. any suggestions?

Yeah, that makes sense. I definitely sympathize with the difficulty of writing complex pipelines. You could try using bson.UnmarshalExtJSON for this and that should do what you want. I wrote up a small example for this at JSON pipeline stages · GitHub and it seems to work as expected.

The only shortcoming is that the input must be a document, but aggregation pipelines are arrays. The workaround in the code I linked above is to define a separate JSON document for each stage and pass all of the stages into the buildPipeline function. Hope this helps!

– Divjot

Hello Divjot, Thank you much! Really appreciated by your in-time and effectively support!