summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline/document_source_geo_near.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/pipeline/document_source_geo_near.cpp')
-rw-r--r--src/mongo/db/pipeline/document_source_geo_near.cpp288
1 files changed, 143 insertions, 145 deletions
diff --git a/src/mongo/db/pipeline/document_source_geo_near.cpp b/src/mongo/db/pipeline/document_source_geo_near.cpp
index 20ba3e2dadc..c66702480fc 100644
--- a/src/mongo/db/pipeline/document_source_geo_near.cpp
+++ b/src/mongo/db/pipeline/document_source_geo_near.cpp
@@ -36,197 +36,195 @@
namespace mongo {
- using boost::intrusive_ptr;
- using std::min;
+using boost::intrusive_ptr;
+using std::min;
- char DocumentSourceGeoNear::geoNearName[] = "$geoNear";
- const char *DocumentSourceGeoNear::getSourceName() const { return geoNearName; }
-
- boost::optional<Document> DocumentSourceGeoNear::getNext() {
- pExpCtx->checkForInterrupt();
+char DocumentSourceGeoNear::geoNearName[] = "$geoNear";
+const char* DocumentSourceGeoNear::getSourceName() const {
+ return geoNearName;
+}
- if (!resultsIterator)
- runCommand();
+boost::optional<Document> DocumentSourceGeoNear::getNext() {
+ pExpCtx->checkForInterrupt();
- if (!resultsIterator->more())
- return boost::none;
+ if (!resultsIterator)
+ runCommand();
- // each result from the geoNear command is wrapped in a wrapper object with "obj",
- // "dis" and maybe "loc" fields. We want to take the object from "obj" and inject the
- // other fields into it.
- Document result (resultsIterator->next().embeddedObject());
- MutableDocument output (result["obj"].getDocument());
- output.setNestedField(*distanceField, result["dis"]);
- if (includeLocs)
- output.setNestedField(*includeLocs, result["loc"]);
+ if (!resultsIterator->more())
+ return boost::none;
- return output.freeze();
- }
+ // each result from the geoNear command is wrapped in a wrapper object with "obj",
+ // "dis" and maybe "loc" fields. We want to take the object from "obj" and inject the
+ // other fields into it.
+ Document result(resultsIterator->next().embeddedObject());
+ MutableDocument output(result["obj"].getDocument());
+ output.setNestedField(*distanceField, result["dis"]);
+ if (includeLocs)
+ output.setNestedField(*includeLocs, result["loc"]);
- void DocumentSourceGeoNear::setSource(DocumentSource*) {
- uasserted(16602, "$geoNear is only allowed as the first pipeline stage");
- }
+ return output.freeze();
+}
- bool DocumentSourceGeoNear::coalesce(const intrusive_ptr<DocumentSource> &pNextSource) {
- DocumentSourceLimit* limitSrc = dynamic_cast<DocumentSourceLimit*>(pNextSource.get());
- if (limitSrc) {
- limit = min(limit, limitSrc->getLimit());
- return true;
- }
+void DocumentSourceGeoNear::setSource(DocumentSource*) {
+ uasserted(16602, "$geoNear is only allowed as the first pipeline stage");
+}
- return false;
+bool DocumentSourceGeoNear::coalesce(const intrusive_ptr<DocumentSource>& pNextSource) {
+ DocumentSourceLimit* limitSrc = dynamic_cast<DocumentSourceLimit*>(pNextSource.get());
+ if (limitSrc) {
+ limit = min(limit, limitSrc->getLimit());
+ return true;
}
- // This command is sent as-is to the shards.
- // On router this becomes a sort by distance (nearest-first) with limit.
- intrusive_ptr<DocumentSource> DocumentSourceGeoNear::getShardSource() { return this; }
- intrusive_ptr<DocumentSource> DocumentSourceGeoNear::getMergeSource() {
- return DocumentSourceSort::create(pExpCtx,
- BSON(distanceField->getPath(false) << 1),
- limit);
- }
+ return false;
+}
- Value DocumentSourceGeoNear::serialize(bool explain) const {
- MutableDocument result;
+// This command is sent as-is to the shards.
+// On router this becomes a sort by distance (nearest-first) with limit.
+intrusive_ptr<DocumentSource> DocumentSourceGeoNear::getShardSource() {
+ return this;
+}
+intrusive_ptr<DocumentSource> DocumentSourceGeoNear::getMergeSource() {
+ return DocumentSourceSort::create(pExpCtx, BSON(distanceField->getPath(false) << 1), limit);
+}
- if (coordsIsArray) {
- result.setField("near", Value(BSONArray(coords)));
- }
- else {
- result.setField("near", Value(coords));
- }
+Value DocumentSourceGeoNear::serialize(bool explain) const {
+ MutableDocument result;
- // not in buildGeoNearCmd
- result.setField("distanceField", Value(distanceField->getPath(false)));
+ if (coordsIsArray) {
+ result.setField("near", Value(BSONArray(coords)));
+ } else {
+ result.setField("near", Value(coords));
+ }
- result.setField("limit", Value(limit));
+ // not in buildGeoNearCmd
+ result.setField("distanceField", Value(distanceField->getPath(false)));
- if (maxDistance > 0)
- result.setField("maxDistance", Value(maxDistance));
+ result.setField("limit", Value(limit));
- if (minDistance > 0)
- result.setField("minDistance", Value(minDistance));
+ if (maxDistance > 0)
+ result.setField("maxDistance", Value(maxDistance));
- result.setField("query", Value(query));
- result.setField("spherical", Value(spherical));
- result.setField("distanceMultiplier", Value(distanceMultiplier));
+ if (minDistance > 0)
+ result.setField("minDistance", Value(minDistance));
- if (includeLocs)
- result.setField("includeLocs", Value(includeLocs->getPath(false)));
+ result.setField("query", Value(query));
+ result.setField("spherical", Value(spherical));
+ result.setField("distanceMultiplier", Value(distanceMultiplier));
- return Value(DOC(getSourceName() << result.freeze()));
- }
+ if (includeLocs)
+ result.setField("includeLocs", Value(includeLocs->getPath(false)));
- BSONObj DocumentSourceGeoNear::buildGeoNearCmd() const {
- // this is very similar to sourceToBson, but slightly different.
- // differences will be noted.
+ return Value(DOC(getSourceName() << result.freeze()));
+}
- BSONObjBuilder geoNear; // not building a subField
+BSONObj DocumentSourceGeoNear::buildGeoNearCmd() const {
+ // this is very similar to sourceToBson, but slightly different.
+ // differences will be noted.
- geoNear.append("geoNear", pExpCtx->ns.coll()); // not in toBson
+ BSONObjBuilder geoNear; // not building a subField
- if (coordsIsArray) {
- geoNear.appendArray("near", coords);
- }
- else {
- geoNear.append("near", coords);
- }
+ geoNear.append("geoNear", pExpCtx->ns.coll()); // not in toBson
- geoNear.append("num", limit); // called limit in toBson
+ if (coordsIsArray) {
+ geoNear.appendArray("near", coords);
+ } else {
+ geoNear.append("near", coords);
+ }
- if (maxDistance > 0)
- geoNear.append("maxDistance", maxDistance);
+ geoNear.append("num", limit); // called limit in toBson
- if (minDistance > 0)
- geoNear.append("minDistance", minDistance);
+ if (maxDistance > 0)
+ geoNear.append("maxDistance", maxDistance);
- geoNear.append("query", query);
- geoNear.append("spherical", spherical);
- geoNear.append("distanceMultiplier", distanceMultiplier);
+ if (minDistance > 0)
+ geoNear.append("minDistance", minDistance);
- if (includeLocs)
- geoNear.append("includeLocs", true); // String in toBson
+ geoNear.append("query", query);
+ geoNear.append("spherical", spherical);
+ geoNear.append("distanceMultiplier", distanceMultiplier);
- return geoNear.obj();
- }
+ if (includeLocs)
+ geoNear.append("includeLocs", true); // String in toBson
- void DocumentSourceGeoNear::runCommand() {
- massert(16603, "Already ran geoNearCommand",
- !resultsIterator);
+ return geoNear.obj();
+}
- bool ok = _mongod->directClient()->runCommand(pExpCtx->ns.db().toString(),
- buildGeoNearCmd(),
- cmdOutput);
- uassert(16604, "geoNear command failed: " + cmdOutput.toString(),
- ok);
+void DocumentSourceGeoNear::runCommand() {
+ massert(16603, "Already ran geoNearCommand", !resultsIterator);
- resultsIterator.reset(new BSONObjIterator(cmdOutput["results"].embeddedObject()));
- }
+ bool ok = _mongod->directClient()->runCommand(
+ pExpCtx->ns.db().toString(), buildGeoNearCmd(), cmdOutput);
+ uassert(16604, "geoNear command failed: " + cmdOutput.toString(), ok);
- intrusive_ptr<DocumentSourceGeoNear> DocumentSourceGeoNear::create(
- const intrusive_ptr<ExpressionContext> &pCtx) {
- return new DocumentSourceGeoNear(pCtx);
- }
+ resultsIterator.reset(new BSONObjIterator(cmdOutput["results"].embeddedObject()));
+}
- intrusive_ptr<DocumentSource> DocumentSourceGeoNear::createFromBson(
- BSONElement elem,
- const intrusive_ptr<ExpressionContext> &pCtx) {
- intrusive_ptr<DocumentSourceGeoNear> out = new DocumentSourceGeoNear(pCtx);
- out->parseOptions(elem.embeddedObjectUserCheck());
- return out;
- }
+intrusive_ptr<DocumentSourceGeoNear> DocumentSourceGeoNear::create(
+ const intrusive_ptr<ExpressionContext>& pCtx) {
+ return new DocumentSourceGeoNear(pCtx);
+}
- void DocumentSourceGeoNear::parseOptions(BSONObj options) {
- // near and distanceField are required
+intrusive_ptr<DocumentSource> DocumentSourceGeoNear::createFromBson(
+ BSONElement elem, const intrusive_ptr<ExpressionContext>& pCtx) {
+ intrusive_ptr<DocumentSourceGeoNear> out = new DocumentSourceGeoNear(pCtx);
+ out->parseOptions(elem.embeddedObjectUserCheck());
+ return out;
+}
- uassert(16605, "$geoNear requires a 'near' option as an Array",
- options["near"].isABSONObj()); // Array or Object (Object is deprecated)
- coordsIsArray = options["near"].type() == Array;
- coords = options["near"].embeddedObject().getOwned();
+void DocumentSourceGeoNear::parseOptions(BSONObj options) {
+ // near and distanceField are required
- uassert(16606, "$geoNear requires a 'distanceField' option as a String",
- options["distanceField"].type() == String);
- distanceField.reset(new FieldPath(options["distanceField"].str()));
+ uassert(16605,
+ "$geoNear requires a 'near' option as an Array",
+ options["near"].isABSONObj()); // Array or Object (Object is deprecated)
+ coordsIsArray = options["near"].type() == Array;
+ coords = options["near"].embeddedObject().getOwned();
- // remaining fields are optional
+ uassert(16606,
+ "$geoNear requires a 'distanceField' option as a String",
+ options["distanceField"].type() == String);
+ distanceField.reset(new FieldPath(options["distanceField"].str()));
- // num and limit are synonyms
- if (options["limit"].isNumber())
- limit = options["limit"].numberLong();
- if (options["num"].isNumber())
- limit = options["num"].numberLong();
+ // remaining fields are optional
- if (options["maxDistance"].isNumber())
- maxDistance = options["maxDistance"].numberDouble();
+ // num and limit are synonyms
+ if (options["limit"].isNumber())
+ limit = options["limit"].numberLong();
+ if (options["num"].isNumber())
+ limit = options["num"].numberLong();
- if (options["minDistance"].isNumber())
- minDistance = options["minDistance"].numberDouble();
+ if (options["maxDistance"].isNumber())
+ maxDistance = options["maxDistance"].numberDouble();
- if (options["query"].type() == Object)
- query = options["query"].embeddedObject().getOwned();
+ if (options["minDistance"].isNumber())
+ minDistance = options["minDistance"].numberDouble();
- spherical = options["spherical"].trueValue();
+ if (options["query"].type() == Object)
+ query = options["query"].embeddedObject().getOwned();
- if (options["distanceMultiplier"].isNumber())
- distanceMultiplier = options["distanceMultiplier"].numberDouble();
+ spherical = options["spherical"].trueValue();
- if (options.hasField("includeLocs")) {
- uassert(16607, "$geoNear requires that 'includeLocs' option is a String",
- options["includeLocs"].type() == String);
- includeLocs.reset(new FieldPath(options["includeLocs"].str()));
- }
+ if (options["distanceMultiplier"].isNumber())
+ distanceMultiplier = options["distanceMultiplier"].numberDouble();
- if (options.hasField("uniqueDocs"))
- warning() << "ignoring deprecated uniqueDocs option in $geoNear aggregation stage";
+ if (options.hasField("includeLocs")) {
+ uassert(16607,
+ "$geoNear requires that 'includeLocs' option is a String",
+ options["includeLocs"].type() == String);
+ includeLocs.reset(new FieldPath(options["includeLocs"].str()));
}
- DocumentSourceGeoNear::DocumentSourceGeoNear(const intrusive_ptr<ExpressionContext> &pExpCtx)
- : DocumentSource(pExpCtx)
- , coordsIsArray(false)
- , limit(100)
- , maxDistance(-1.0)
- , minDistance(-1.0)
- , spherical(false)
- , distanceMultiplier(1.0)
- {}
+ if (options.hasField("uniqueDocs"))
+ warning() << "ignoring deprecated uniqueDocs option in $geoNear aggregation stage";
+}
+
+DocumentSourceGeoNear::DocumentSourceGeoNear(const intrusive_ptr<ExpressionContext>& pExpCtx)
+ : DocumentSource(pExpCtx),
+ coordsIsArray(false),
+ limit(100),
+ maxDistance(-1.0),
+ minDistance(-1.0),
+ spherical(false),
+ distanceMultiplier(1.0) {}
}