bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string ns = dbname + "." + cmdObj.firstElement().valuestr(); NamespaceDetails *d = nsdetails(ns); if (NULL == d) { errmsg = "can't find ns"; return false; } GeoNearArguments commonArgs(cmdObj); if (commonArgs.numWanted < 0) { errmsg = "numWanted must be >= 0"; return false; } vector<int> idxs; d->findIndexByType(IndexNames::GEO_2D, idxs); if (idxs.size() > 1) { errmsg = "more than one 2d index, not sure which to run geoNear on"; return false; } unordered_map<string, double> statsMap; if (1 == idxs.size()) { result.append("ns", ns); twod_internal::TwoDGeoNearRunner::run2DGeoNear(d, idxs[0], cmdObj, commonArgs, errmsg, result, &statsMap); BSONObjBuilder stats(result.subobjStart("stats")); for (unordered_map<string, double>::const_iterator it = statsMap.begin(); it != statsMap.end(); ++it) { stats.append(it->first, it->second); } stats.append("time", cc().curop()->elapsedMillis()); stats.done(); return true; } d->findIndexByType(IndexNames::GEO_2DSPHERE, idxs); if (idxs.size() > 1) { errmsg = "more than one 2dsphere index, not sure which to run geoNear on"; return false; } if (1 == idxs.size()) { result.append("ns", ns); run2DSphereGeoNear(d, idxs[0], cmdObj, commonArgs, errmsg, result); return true; } errmsg = "no geo indices for geoNear"; return false; }
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string ns = dbname + "." + cmdObj.firstElement().valuestr(); NamespaceDetails *d = nsdetails(ns); if (NULL == d) { errmsg = "can't find ns"; return false; } GeoNearArguments commonArgs(cmdObj); if (commonArgs.numWanted < 0) { errmsg = "numWanted must be >= 0"; return false; } vector<int> idxs; d->findIndexByType("2d", idxs); if (idxs.size() > 1) { errmsg = "more than one 2d index, not sure which to run geoNear on"; return false; } if (1 == idxs.size()) { result.append("ns", ns); return run2DGeoNear(d->idx(idxs[0]), cmdObj, commonArgs, errmsg, result); } d->findIndexByType("2dsphere", idxs); if (idxs.size() > 1) { errmsg = "more than one 2dsphere index, not sure which to run geoNear on"; return false; } if (1 == idxs.size()) { result.append("ns", ns); return run2DSphereGeoNear(d->idx(idxs[0]), cmdObj, commonArgs, errmsg, result); } errmsg = "no geo indices for geoNear"; return false; }
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string ns = dbname + "." + cmdObj.firstElement().valuestr(); NamespaceDetails *nsd = nsdetails(ns); if (NULL == nsd) { errmsg = "can't find ns"; return false; } vector<int> idxs; nsd->findIndexByType(GEOSEARCHNAME, idxs); if (idxs.size() == 0) { errmsg = "no geoSearch index"; return false; } if (idxs.size() > 1) { errmsg = "more than 1 geosearch index"; return false; } BSONElement nearElt = cmdObj["near"]; BSONElement maxDistance = cmdObj["maxDistance"]; BSONElement search = cmdObj["search"]; uassert(13318, "near needs to be an array", nearElt.isABSONObj()); uassert(13319, "maxDistance needs a number", maxDistance.isNumber()); uassert(13320, "search needs to be an object", search.type() == Object); unsigned limit = 50; if (cmdObj["limit"].isNumber()) limit = static_cast<unsigned>(cmdObj["limit"].numberInt()); int idxNum = idxs[0]; IndexDetails& id = nsd->idx(idxNum); if (CatalogHack::testIndexMigration()) { auto_ptr<IndexDescriptor> desc(CatalogHack::getDescriptor(nsd, idxNum)); auto_ptr<HaystackAccessMethod> ham(new HaystackAccessMethod(desc.get())); ham->searchCommand(nearElt.Obj(), maxDistance.numberDouble(), search.Obj(), &result, limit); } else { GeoHaystackSearchIndex *si = static_cast<GeoHaystackSearchIndex*>(id.getSpec().getType()); verify(&id == si->getDetails()); si->searchCommand(nsd, nearElt.Obj(), maxDistance.numberDouble(), search.Obj(), result, limit); } return 1; }
bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string ns = dbname + "." + cmdObj.firstElement().valuestr(); NamespaceDetails * d = nsdetails( ns.c_str() ); if ( ! d ) { errmsg = "can't find ns"; return false; } vector<int> idxs; d->findIndexByType( GEOSEARCHNAME , idxs ); if ( idxs.size() == 0 ) { errmsg = "no geoSearch index"; return false; } if ( idxs.size() > 1 ) { errmsg = "more than 1 geosearch index"; return false; } int idxNum = idxs[0]; IndexDetails& id = d->idx( idxNum ); GeoHaystackSearchIndex * si = (GeoHaystackSearchIndex*)id.getSpec().getType(); verify( &id == si->getDetails() ); BSONElement n = cmdObj["near"]; BSONElement maxDistance = cmdObj["maxDistance"]; BSONElement search = cmdObj["search"]; uassert( 13318 , "near needs to be an array" , n.isABSONObj() ); uassert( 13319 , "maxDistance needs a number" , maxDistance.isNumber() ); uassert( 13320 , "search needs to be an object" , search.type() == Object ); unsigned limit = 50; if ( cmdObj["limit"].isNumber() ) limit = (unsigned)cmdObj["limit"].numberInt(); si->searchCommand( d , idxNum , n.Obj() , maxDistance.numberDouble() , search.Obj() , result , limit ); return 1; }
PlanStage* buildStages(const string& ns, const QuerySolutionNode* root, WorkingSet* ws) { if (STAGE_COLLSCAN == root->getType()) { const CollectionScanNode* csn = static_cast<const CollectionScanNode*>(root); CollectionScanParams params; params.ns = csn->name; params.tailable = csn->tailable; params.direction = (csn->direction == 1) ? CollectionScanParams::FORWARD : CollectionScanParams::BACKWARD; return new CollectionScan(params, ws, csn->filter.get()); } else if (STAGE_IXSCAN == root->getType()) { const IndexScanNode* ixn = static_cast<const IndexScanNode*>(root); // // XXX XXX // Given that this grabs data from the catalog, we must do this inside of a lock. // We should change this to take a (ns, index key pattern) pair so that the params // don't involve any on-disk data, just descriptions thereof. // XXX XXX // IndexScanParams params; NamespaceDetails* nsd = nsdetails(ns.c_str()); if (NULL == nsd) { warning() << "Can't ixscan null ns " << ns << endl; return NULL; } int idxNo = nsd->findIndexByKeyPattern(ixn->indexKeyPattern); if (-1 == idxNo) { warning() << "Can't find idx " << ixn->indexKeyPattern.toString() << "in ns " << ns << endl; return NULL; } params.descriptor = CatalogHack::getDescriptor(nsd, idxNo); params.bounds = ixn->bounds; params.direction = ixn->direction; params.limit = ixn->limit; return new IndexScan(params, ws, ixn->filter.get()); } else if (STAGE_FETCH == root->getType()) { const FetchNode* fn = static_cast<const FetchNode*>(root); PlanStage* childStage = buildStages(ns, fn->child.get(), ws); if (NULL == childStage) { return NULL; } return new FetchStage(ws, childStage, fn->filter.get()); } else if (STAGE_SORT == root->getType()) { const SortNode* sn = static_cast<const SortNode*>(root); PlanStage* childStage = buildStages(ns, sn->child.get(), ws); if (NULL == childStage) { return NULL; } SortStageParams params; params.pattern = sn->pattern; return new SortStage(params, ws, childStage); } else if (STAGE_PROJECTION == root->getType()) { const ProjectionNode* pn = static_cast<const ProjectionNode*>(root); PlanStage* childStage = buildStages(ns, pn->child.get(), ws); if (NULL == childStage) { return NULL; } return new ProjectionStage(pn->projection, ws, childStage, NULL); } else if (STAGE_LIMIT == root->getType()) { const LimitNode* ln = static_cast<const LimitNode*>(root); PlanStage* childStage = buildStages(ns, ln->child.get(), ws); if (NULL == childStage) { return NULL; } return new LimitStage(ln->limit, ws, childStage); } else if (STAGE_SKIP == root->getType()) { const SkipNode* sn = static_cast<const SkipNode*>(root); PlanStage* childStage = buildStages(ns, sn->child.get(), ws); if (NULL == childStage) { return NULL; } return new SkipStage(sn->skip, ws, childStage); } else if (STAGE_AND_HASH == root->getType()) { const AndHashNode* ahn = static_cast<const AndHashNode*>(root); auto_ptr<AndHashStage> ret(new AndHashStage(ws, ahn->filter.get())); for (size_t i = 0; i < ahn->children.size(); ++i) { PlanStage* childStage = buildStages(ns, ahn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } return ret.release(); } else if (STAGE_OR == root->getType()) { const OrNode * orn = static_cast<const OrNode*>(root); auto_ptr<OrStage> ret(new OrStage(ws, orn->dedup, orn->filter.get())); for (size_t i = 0; i < orn->children.size(); ++i) { PlanStage* childStage = buildStages(ns, orn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } return ret.release(); } else if (STAGE_AND_SORTED == root->getType()) { const AndSortedNode* asn = static_cast<const AndSortedNode*>(root); auto_ptr<AndSortedStage> ret(new AndSortedStage(ws, asn->filter.get())); for (size_t i = 0; i < asn->children.size(); ++i) { PlanStage* childStage = buildStages(ns, asn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } return ret.release(); } else if (STAGE_SORT_MERGE == root->getType()) { const MergeSortNode* msn = static_cast<const MergeSortNode*>(root); MergeSortStageParams params; params.dedup = msn->dedup; params.pattern = msn->sort; auto_ptr<MergeSortStage> ret(new MergeSortStage(params, ws)); for (size_t i = 0; i < msn->children.size(); ++i) { PlanStage* childStage = buildStages(ns, msn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } return ret.release(); } else if (STAGE_GEO_2D == root->getType()) { const Geo2DNode* node = static_cast<const Geo2DNode*>(root); TwoDParams params; params.gq = node->gq; params.filter = node->filter.get(); params.indexKeyPattern = node->indexKeyPattern; params.ns = ns; return new TwoD(params, ws); } else if (STAGE_GEO_NEAR_2D == root->getType()) { const GeoNear2DNode* node = static_cast<const GeoNear2DNode*>(root); TwoDNearParams params; params.nearQuery = node->nq; params.ns = ns; params.indexKeyPattern = node->indexKeyPattern; params.filter = node->filter.get(); params.numWanted = node->numWanted; // XXX XXX where do we grab this from?? the near query...modify geo parser... :( params.uniqueDocs = false; // XXX XXX where do we grab this from?? the near query...modify geo parser... :( return new TwoDNear(params, ws); } else if (STAGE_GEO_NEAR_2DSPHERE == root->getType()) { const GeoNear2DSphereNode* node = static_cast<const GeoNear2DSphereNode*>(root); return new S2NearStage(ns, node->indexKeyPattern, node->nq, node->baseBounds, node->filter.get(), ws); } else if (STAGE_TEXT == root->getType()) { const TextNode* node = static_cast<const TextNode*>(root); NamespaceDetails* nsd = nsdetails(ns.c_str()); if (NULL == nsd) { return NULL; } vector<int> idxMatches; nsd->findIndexByType("text", idxMatches); if (1 != idxMatches.size()) { return NULL; } IndexDescriptor* index = CatalogHack::getDescriptor(nsd, idxMatches[0]); auto_ptr<FTSAccessMethod> fam(new FTSAccessMethod(index)); TextStageParams params(fam->getSpec()); params.ns = ns; params.index = index; params.spec = fam->getSpec(); params.limit = node->_numWanted; Status s = fam->getSpec().getIndexPrefix(BSONObj(), ¶ms.indexPrefix); if (!s.isOK()) { return NULL; } string language = ("" == node->_language ? fam->getSpec().defaultLanguage() : node->_language); FTSQuery ftsq; Status parseStatus = ftsq.parse(node->_query, language); if (!parseStatus.isOK()) { return NULL; } params.query = ftsq; return new TextStage(params, ws, node->_filter.get()); } else { stringstream ss; root->appendToString(&ss, 0); warning() << "Could not build exec tree for node " << ss.str() << endl; return NULL; } }