diff options
Diffstat (limited to 'src/mongo/db/pipeline/document_source_geo_near.cpp')
-rw-r--r-- | src/mongo/db/pipeline/document_source_geo_near.cpp | 288 |
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) {} } |