本文整理汇总了C++中MatchExpression::numChildren方法的典型用法代码示例。如果您正苦于以下问题:C++ MatchExpression::numChildren方法的具体用法?C++ MatchExpression::numChildren怎么用?C++ MatchExpression::numChildren使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类MatchExpression
的用法示例。
在下文中一共展示了MatchExpression::numChildren方法的11个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: planSubqueries
Status SubplanRunner::planSubqueries() {
MatchExpression* theOr = _query->root();
for (size_t i = 0; i < _plannerParams.indices.size(); ++i) {
const IndexEntry& ie = _plannerParams.indices[i];
_indexMap[ie.keyPattern] = i;
QLOG() << "Subplanner: index " << i << " is " << ie.toString() << endl;
}
const WhereCallbackReal whereCallback(_collection->ns().db());
for (size_t i = 0; i < theOr->numChildren(); ++i) {
// Turn the i-th child into its own query.
MatchExpression* orChild = theOr->getChild(i);
CanonicalQuery* orChildCQ;
Status childCQStatus = CanonicalQuery::canonicalize(*_query,
orChild,
&orChildCQ,
whereCallback);
if (!childCQStatus.isOK()) {
mongoutils::str::stream ss;
ss << "Subplanner: Can't canonicalize subchild " << orChild->toString()
<< " " << childCQStatus.reason();
return Status(ErrorCodes::BadValue, ss);
}
// Make sure it gets cleaned up.
auto_ptr<CanonicalQuery> safeOrChildCQ(orChildCQ);
// Plan the i-th child.
vector<QuerySolution*> solutions;
// We don't set NO_TABLE_SCAN because peeking at the cache data will keep us from
// considering any plan that's a collscan.
QLOG() << "Subplanner: planning child " << i << " of " << theOr->numChildren();
Status status = QueryPlanner::plan(*safeOrChildCQ, _plannerParams, &solutions);
if (!status.isOK()) {
mongoutils::str::stream ss;
ss << "Subplanner: Can't plan for subchild " << orChildCQ->toString()
<< " " << status.reason();
return Status(ErrorCodes::BadValue, ss);
}
QLOG() << "Subplanner: got " << solutions.size() << " solutions";
if (0 == solutions.size()) {
// If one child doesn't have an indexed solution, bail out.
mongoutils::str::stream ss;
ss << "Subplanner: No solutions for subchild " << orChildCQ->toString();
return Status(ErrorCodes::BadValue, ss);
}
// Hang onto the canonicalized subqueries and the corresponding query solutions
// so that they can be used in subplan running later on.
_cqs.push(safeOrChildCQ.release());
_solutions.push(solutions);
}
return Status::OK();
}
示例2: normalizeTree
// static
MatchExpression* CanonicalQuery::normalizeTree(MatchExpression* root) {
// root->isLogical() is true now. We care about AND, OR, and NOT. NOR currently scares us.
if (MatchExpression::AND == root->matchType() || MatchExpression::OR == root->matchType()) {
// We could have AND of AND of AND. Make sure we clean up our children before merging
// them.
// UNITTEST 11738048
for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
(*root->getChildVector())[i] = normalizeTree(root->getChild(i));
}
// If any of our children are of the same logical operator that we are, we remove the
// child's children and append them to ourselves after we examine all children.
std::vector<MatchExpression*> absorbedChildren;
for (size_t i = 0; i < root->numChildren();) {
MatchExpression* child = root->getChild(i);
if (child->matchType() == root->matchType()) {
// AND of an AND or OR of an OR. Absorb child's children into ourself.
for (size_t j = 0; j < child->numChildren(); ++j) {
absorbedChildren.push_back(child->getChild(j));
}
// TODO(opt): this is possibly n^2-ish
root->getChildVector()->erase(root->getChildVector()->begin() + i);
child->getChildVector()->clear();
// Note that this only works because we cleared the child's children
delete child;
// Don't increment 'i' as the current child 'i' used to be child 'i+1'
} else {
++i;
}
}
root->getChildVector()->insert(
root->getChildVector()->end(), absorbedChildren.begin(), absorbedChildren.end());
// AND of 1 thing is the thing, OR of 1 thing is the thing.
if (1 == root->numChildren()) {
MatchExpression* ret = root->getChild(0);
root->getChildVector()->clear();
delete root;
return ret;
}
} else if (MatchExpression::NOT == root->matchType()) {
// Normalize the rest of the tree hanging off this NOT node.
NotMatchExpression* nme = static_cast<NotMatchExpression*>(root);
MatchExpression* child = nme->releaseChild();
// normalizeTree(...) takes ownership of 'child', and then
// transfers ownership of its return value to 'nme'.
nme->resetChild(normalizeTree(child));
} else if (MatchExpression::ELEM_MATCH_VALUE == root->matchType()) {
// Just normalize our children.
for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
(*root->getChildVector())[i] = normalizeTree(root->getChild(i));
}
}
return root;
}
示例3: normalizeTree
// static
MatchExpression* CanonicalQuery::normalizeTree(MatchExpression* root) {
// root->isLogical() is true now. We care about AND and OR. Negations currently scare us.
if (MatchExpression::AND == root->matchType() || MatchExpression::OR == root->matchType()) {
// We could have AND of AND of AND. Make sure we clean up our children before merging
// them.
// UNITTEST 11738048
for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
(*root->getChildVector())[i] = normalizeTree(root->getChild(i));
}
// If any of our children are of the same logical operator that we are, we remove the
// child's children and append them to ourselves after we examine all children.
vector<MatchExpression*> absorbedChildren;
for (size_t i = 0; i < root->numChildren();) {
MatchExpression* child = root->getChild(i);
if (child->matchType() == root->matchType()) {
// AND of an AND or OR of an OR. Absorb child's children into ourself.
for (size_t j = 0; j < child->numChildren(); ++j) {
absorbedChildren.push_back(child->getChild(j));
}
// TODO(opt): this is possibly n^2-ish
root->getChildVector()->erase(root->getChildVector()->begin() + i);
child->getChildVector()->clear();
// Note that this only works because we cleared the child's children
delete child;
// Don't increment 'i' as the current child 'i' used to be child 'i+1'
}
else {
++i;
}
}
root->getChildVector()->insert(root->getChildVector()->end(),
absorbedChildren.begin(),
absorbedChildren.end());
// AND of 1 thing is the thing, OR of 1 thing is the thing.
if (1 == root->numChildren()) {
MatchExpression* ret = root->getChild(0);
root->getChildVector()->clear();
delete root;
return ret;
}
}
return root;
}
示例4: isIndependentOf
bool isIndependentOf(const MatchExpression& expr, const std::set<std::string>& pathSet) {
if (expr.isLogical()) {
// Any logical expression is independent of 'pathSet' if all its children are independent of
// 'pathSet'.
for (size_t i = 0; i < expr.numChildren(); i++) {
if (!isIndependentOf(*expr.getChild(i), pathSet)) {
return false;
}
}
return true;
}
// At this point, we know 'expr' is a leaf. If it is an elemMatch, we do not attempt to
// determine if it is independent or not, and instead just return false.
return !isElemMatch(expr) && isLeafIndependentOf(expr.path(), pathSet);
}
示例5: _extractFullEqualityMatches
static Status _extractFullEqualityMatches(const MatchExpression& root,
const FieldRefSet* fullPathsToExtract,
EqualityMatches* equalities) {
if (root.matchType() == MatchExpression::EQ) {
// Extract equality matches
const EqualityMatchExpression& eqChild =
static_cast<const EqualityMatchExpression&>(root);
FieldRef path(eqChild.path());
if (fullPathsToExtract) {
FieldRefSet conflictPaths;
fullPathsToExtract->findConflicts(&path, &conflictPaths);
// Ignore if this path is unrelated to the full paths
if (conflictPaths.empty())
return Status::OK();
// Make sure we're a prefix of all the conflict paths
Status status = checkPathIsPrefixOf(path, conflictPaths);
if (!status.isOK())
return status;
}
Status status = checkEqualityConflicts(*equalities, path);
if (!status.isOK())
return status;
equalities->insert(make_pair(eqChild.path(), &eqChild));
}
else if (root.matchType() == MatchExpression::AND) {
// Further explore $and matches
for (size_t i = 0; i < root.numChildren(); ++i) {
MatchExpression* child = root.getChild(i);
Status status = _extractFullEqualityMatches(*child, fullPathsToExtract, equalities);
if (!status.isOK())
return status;
}
}
return Status::OK();
}
示例6: planSubqueries
Status SubplanStage::planSubqueries() {
// Adds the amount of time taken by planSubqueries() to executionTimeMillis. There's lots of
// work that happens here, so this is needed for the time accounting to make sense.
ScopedTimer timer(&_commonStats.executionTimeMillis);
MatchExpression* orExpr = _query->root();
for (size_t i = 0; i < _plannerParams.indices.size(); ++i) {
const IndexEntry& ie = _plannerParams.indices[i];
_indexMap[ie.keyPattern] = i;
QLOG() << "Subplanner: index " << i << " is " << ie.toString() << endl;
}
const WhereCallbackReal whereCallback(_txn, _collection->ns().db());
for (size_t i = 0; i < orExpr->numChildren(); ++i) {
// We need a place to shove the results from planning this branch.
_branchResults.push_back(new BranchPlanningResult());
BranchPlanningResult* branchResult = _branchResults.back();
MatchExpression* orChild = orExpr->getChild(i);
// Turn the i-th child into its own query.
{
CanonicalQuery* orChildCQ;
Status childCQStatus = CanonicalQuery::canonicalize(*_query,
orChild,
&orChildCQ,
whereCallback);
if (!childCQStatus.isOK()) {
mongoutils::str::stream ss;
ss << "Can't canonicalize subchild " << orChild->toString()
<< " " << childCQStatus.reason();
return Status(ErrorCodes::BadValue, ss);
}
branchResult->canonicalQuery.reset(orChildCQ);
}
// Plan the i-th child. We might be able to find a plan for the i-th child in the plan
// cache. If there's no cached plan, then we generate and rank plans using the MPS.
CachedSolution* rawCS;
if (PlanCache::shouldCacheQuery(*branchResult->canonicalQuery.get()) &&
_collection->infoCache()->getPlanCache()->get(*branchResult->canonicalQuery.get(),
&rawCS).isOK()) {
// We have a CachedSolution. Store it for later.
QLOG() << "Subplanner: cached plan found for child " << i << " of "
<< orExpr->numChildren();
branchResult->cachedSolution.reset(rawCS);
}
else {
// No CachedSolution found. We'll have to plan from scratch.
QLOG() << "Subplanner: planning child " << i << " of " << orExpr->numChildren();
// We don't set NO_TABLE_SCAN because peeking at the cache data will keep us from
// considering any plan that's a collscan.
Status status = QueryPlanner::plan(*branchResult->canonicalQuery.get(),
_plannerParams,
&branchResult->solutions.mutableVector());
if (!status.isOK()) {
mongoutils::str::stream ss;
ss << "Can't plan for subchild "
<< branchResult->canonicalQuery->toString()
<< " " << status.reason();
return Status(ErrorCodes::BadValue, ss);
}
QLOG() << "Subplanner: got " << branchResult->solutions.size() << " solutions";
if (0 == branchResult->solutions.size()) {
// If one child doesn't have an indexed solution, bail out.
mongoutils::str::stream ss;
ss << "No solutions for subchild " << branchResult->canonicalQuery->toString();
return Status(ErrorCodes::BadValue, ss);
}
}
}
return Status::OK();
}
示例7: normalizeTree
// static
MatchExpression* CanonicalQuery::normalizeTree(MatchExpression* root) {
if (MatchExpression::AND == root->matchType() || MatchExpression::OR == root->matchType()) {
// We could have AND of AND of AND. Make sure we clean up our children before merging them.
for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
(*root->getChildVector())[i] = normalizeTree(root->getChild(i));
}
// If any of our children are of the same logical operator that we are, we remove the
// child's children and append them to ourselves after we examine all children.
std::vector<MatchExpression*> absorbedChildren;
for (size_t i = 0; i < root->numChildren();) {
MatchExpression* child = root->getChild(i);
if (child->matchType() == root->matchType()) {
// AND of an AND or OR of an OR. Absorb child's children into ourself.
for (size_t j = 0; j < child->numChildren(); ++j) {
absorbedChildren.push_back(child->getChild(j));
}
// TODO(opt): this is possibly n^2-ish
root->getChildVector()->erase(root->getChildVector()->begin() + i);
child->getChildVector()->clear();
// Note that this only works because we cleared the child's children
delete child;
// Don't increment 'i' as the current child 'i' used to be child 'i+1'
} else {
++i;
}
}
root->getChildVector()->insert(
root->getChildVector()->end(), absorbedChildren.begin(), absorbedChildren.end());
// AND of 1 thing is the thing, OR of 1 thing is the thing.
if (1 == root->numChildren()) {
MatchExpression* ret = root->getChild(0);
root->getChildVector()->clear();
delete root;
return ret;
}
} else if (MatchExpression::NOR == root->matchType()) {
// First clean up children.
for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
(*root->getChildVector())[i] = normalizeTree(root->getChild(i));
}
// NOR of one thing is NOT of the thing.
if (1 == root->numChildren()) {
// Detach the child and assume ownership.
std::unique_ptr<MatchExpression> child(root->getChild(0));
root->getChildVector()->clear();
// Delete the root when this goes out of scope.
std::unique_ptr<NorMatchExpression> ownedRoot(static_cast<NorMatchExpression*>(root));
// Make a NOT to be the new root and transfer ownership of the child to it.
auto newRoot = stdx::make_unique<NotMatchExpression>();
newRoot->init(child.release()).transitional_ignore();
return newRoot.release();
}
} else if (MatchExpression::NOT == root->matchType()) {
// Normalize the rest of the tree hanging off this NOT node.
NotMatchExpression* nme = static_cast<NotMatchExpression*>(root);
MatchExpression* child = nme->releaseChild();
// normalizeTree(...) takes ownership of 'child', and then
// transfers ownership of its return value to 'nme'.
nme->resetChild(normalizeTree(child));
} else if (MatchExpression::ELEM_MATCH_OBJECT == root->matchType()) {
// Normalize the rest of the tree hanging off this ELEM_MATCH_OBJECT node.
ElemMatchObjectMatchExpression* emome = static_cast<ElemMatchObjectMatchExpression*>(root);
auto child = emome->releaseChild();
// normalizeTree(...) takes ownership of 'child', and then
// transfers ownership of its return value to 'emome'.
emome->resetChild(std::unique_ptr<MatchExpression>(normalizeTree(child.release())));
} else if (MatchExpression::ELEM_MATCH_VALUE == root->matchType()) {
// Just normalize our children.
for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
(*root->getChildVector())[i] = normalizeTree(root->getChild(i));
}
} else if (MatchExpression::MATCH_IN == root->matchType()) {
std::unique_ptr<InMatchExpression> in(static_cast<InMatchExpression*>(root));
// IN of 1 regex is the regex.
if (in->getRegexes().size() == 1 && in->getEqualities().empty()) {
RegexMatchExpression* childRe = in->getRegexes().begin()->get();
invariant(!childRe->getTag());
// Create a new RegexMatchExpression, because 'childRe' does not have a path.
auto re = stdx::make_unique<RegexMatchExpression>();
re->init(in->path(), childRe->getString(), childRe->getFlags()).transitional_ignore();
if (in->getTag()) {
re->setTag(in->getTag()->clone());
}
return normalizeTree(re.release());
}
// IN of 1 equality is the equality.
if (in->getEqualities().size() == 1 && in->getRegexes().empty()) {
auto eq = stdx::make_unique<EqualityMatchExpression>();
//.........这里部分代码省略.........
示例8: plan
//.........这里部分代码省略.........
unique_ptr<PlanCacheIndexTree> autoData(cacheData);
// This can fail if enumeration makes a mistake.
QuerySolutionNode* solnRoot = QueryPlannerAccess::buildIndexedDataAccess(
query, rawTree, false, relevantIndices, params);
if (NULL == solnRoot) {
continue;
}
QuerySolution* soln = QueryPlannerAnalysis::analyzeDataAccess(query, params, solnRoot);
if (NULL != soln) {
LOG(5) << "Planner: adding solution:" << endl
<< soln->toString();
if (indexTreeStatus.isOK()) {
SolutionCacheData* scd = new SolutionCacheData();
scd->tree.reset(autoData.release());
soln->cacheData.reset(scd);
}
out->push_back(soln);
}
}
}
// Don't leave tags on query tree.
query.root()->resetTag();
LOG(5) << "Planner: outputted " << out->size() << " indexed solutions.\n";
// Produce legible error message for failed OR planning with a TEXT child.
// TODO: support collection scan for non-TEXT children of OR.
if (out->size() == 0 && textNode != NULL && MatchExpression::OR == query.root()->matchType()) {
MatchExpression* root = query.root();
for (size_t i = 0; i < root->numChildren(); ++i) {
if (textNode == root->getChild(i)) {
return Status(ErrorCodes::BadValue,
"Failed to produce a solution for TEXT under OR - "
"other non-TEXT clauses under OR have to be indexed as well.");
}
}
}
// An index was hinted. If there are any solutions, they use the hinted index. If not, we
// scan the entire index to provide results and output that as our plan. This is the
// desired behavior when an index is hinted that is not relevant to the query.
if (!hintIndex.isEmpty()) {
if (0 == out->size()) {
QuerySolution* soln = buildWholeIXSoln(params.indices[hintIndexNumber], query, params);
verify(NULL != soln);
LOG(5) << "Planner: outputting soln that uses hinted index as scan." << endl;
out->push_back(soln);
}
return Status::OK();
}
// If a sort order is requested, there may be an index that provides it, even if that
// index is not over any predicates in the query.
//
if (!query.getParsed().getSort().isEmpty() &&
!QueryPlannerCommon::hasNode(query.root(), MatchExpression::GEO_NEAR) &&
!QueryPlannerCommon::hasNode(query.root(), MatchExpression::TEXT)) {
// See if we have a sort provided from an index already.
// This is implied by the presence of a non-blocking solution.
bool usingIndexToSort = false;
for (size_t i = 0; i < out->size(); ++i) {
QuerySolution* soln = (*out)[i];
示例9: plan
//.........这里部分代码省略.........
MatchExpression* gnNode = NULL;
if (QueryPlannerCommon::hasNode(query.root(), MatchExpression::GEO_NEAR, &gnNode)) {
// No index for GEO_NEAR? No query.
RelevantTag* tag = static_cast<RelevantTag*>(gnNode->getTag());
if (0 == tag->first.size() && 0 == tag->notFirst.size()) {
return;
}
GeoNearMatchExpression* gnme = static_cast<GeoNearMatchExpression*>(gnNode);
vector<size_t> newFirst;
// 2d + GEO_NEAR is annoying. Because 2d's GEO_NEAR isn't streaming we have to embed
// the full query tree inside it as a matcher.
for (size_t i = 0; i < tag->first.size(); ++i) {
// GEO_NEAR has a non-2d index it can use. We can deal w/that in normal planning.
if (!is2DIndex(relevantIndices[tag->first[i]].keyPattern)) {
newFirst.push_back(i);
continue;
}
// If we're here, GEO_NEAR has a 2d index. We create a 2dgeonear plan with the
// entire tree as a filter, if possible.
GeoNear2DNode* solnRoot = new GeoNear2DNode();
solnRoot->nq = gnme->getData();
if (MatchExpression::GEO_NEAR != query.root()->matchType()) {
// root is an AND, clone and delete the GEO_NEAR child.
MatchExpression* filterTree = query.root()->shallowClone();
verify(MatchExpression::AND == filterTree->matchType());
bool foundChild = false;
for (size_t i = 0; i < filterTree->numChildren(); ++i) {
if (MatchExpression::GEO_NEAR == filterTree->getChild(i)->matchType()) {
foundChild = true;
filterTree->getChildVector()->erase(filterTree->getChildVector()->begin() + i);
break;
}
}
verify(foundChild);
solnRoot->filter.reset(filterTree);
}
solnRoot->numWanted = query.getParsed().getNumToReturn();
if (0 == solnRoot->numWanted) {
solnRoot->numWanted = 100;
}
solnRoot->indexKeyPattern = relevantIndices[tag->first[i]].keyPattern;
// Remove the 2d index. 2d can only be the first field, and we know there is
// only one GEO_NEAR, so we don't care if anyone else was assigned it; it'll
// only be first for gnNode.
tag->first.erase(tag->first.begin() + i);
QuerySolution* soln = QueryPlannerAnalysis::analyzeDataAccess(query, params, solnRoot);
if (NULL != soln) {
out->push_back(soln);
}
}
// Continue planning w/non-2d indices tagged for this pred.
tag->first.swap(newFirst);
if (0 == tag->first.size() && 0 == tag->notFirst.size()) {
示例10: populateDocumentWithQueryFields
Status UpdateDriver::populateDocumentWithQueryFields(const CanonicalQuery* query,
mutablebson::Document& doc) const {
MatchExpression* root = query->root();
MatchExpression::MatchType rootType = root->matchType();
// These copies are needed until we apply the modifiers at the end.
std::vector<BSONObj> copies;
// We only care about equality and "and"ed equality fields, everything else is ignored
if (rootType != MatchExpression::EQ && rootType != MatchExpression::AND)
return Status::OK();
if (isDocReplacement()) {
BSONElement idElem = query->getQueryObj().getField("_id");
// Replacement mods need the _id field copied explicitly.
if (idElem.ok()) {
mb::Element elem = doc.makeElement(idElem);
return doc.root().pushFront(elem);
}
return Status::OK();
}
// Create a new UpdateDriver to create the base doc from the query
Options opts;
opts.logOp = false;
opts.multi = false;
opts.upsert = true;
opts.modOptions = modOptions();
UpdateDriver insertDriver(opts);
insertDriver.setContext(ModifierInterface::ExecInfo::INSERT_CONTEXT);
// If we are a single equality match query
if (root->matchType() == MatchExpression::EQ) {
EqualityMatchExpression* eqMatch =
static_cast<EqualityMatchExpression*>(root);
const BSONElement matchData = eqMatch->getData();
BSONElement childElem = matchData;
// Make copy to new path if not the same field name (for cases like $all)
if (!root->path().empty() && matchData.fieldNameStringData() != root->path()) {
BSONObjBuilder copyBuilder;
copyBuilder.appendAs(eqMatch->getData(), root->path());
const BSONObj copy = copyBuilder.obj();
copies.push_back(copy);
childElem = copy[root->path()];
}
// Add this element as a $set modifier
Status s = insertDriver.addAndParse(modifiertable::MOD_SET,
childElem);
if (!s.isOK())
return s;
}
else {
// parse query $set mods, including only equality stuff
for (size_t i = 0; i < root->numChildren(); ++i) {
MatchExpression* child = root->getChild(i);
if (child->matchType() == MatchExpression::EQ) {
EqualityMatchExpression* eqMatch =
static_cast<EqualityMatchExpression*>(child);
const BSONElement matchData = eqMatch->getData();
BSONElement childElem = matchData;
// Make copy to new path if not the same field name (for cases like $all)
if (!child->path().empty() &&
matchData.fieldNameStringData() != child->path()) {
BSONObjBuilder copyBuilder;
copyBuilder.appendAs(eqMatch->getData(), child->path());
const BSONObj copy = copyBuilder.obj();
copies.push_back(copy);
childElem = copy[child->path()];
}
// Add this element as a $set modifier
Status s = insertDriver.addAndParse(modifiertable::MOD_SET,
childElem);
if (!s.isOK())
return s;
}
}
}
// update the document with base field
Status s = insertDriver.update(StringData(), &doc);
copies.clear();
if (!s.isOK()) {
return Status(ErrorCodes::UnsupportedFormat,
str::stream() << "Cannot create base during"
" insert of update. Caused by :"
<< s.toString());
}
//.........这里部分代码省略.........
示例11: plan
//.........这里部分代码省略.........
QLOG() << "unable to find index for $geoNear query" << endl;
return Status(ErrorCodes::BadValue, "unable to find index for $geoNear query");
}
GeoNearMatchExpression* gnme = static_cast<GeoNearMatchExpression*>(gnNode);
vector<size_t> newFirst;
// 2d + GEO_NEAR is annoying. Because 2d's GEO_NEAR isn't streaming we have to embed
// the full query tree inside it as a matcher.
for (size_t i = 0; i < tag->first.size(); ++i) {
// GEO_NEAR has a non-2d index it can use. We can deal w/that in normal planning.
if (!is2DIndex(relevantIndices[tag->first[i]].keyPattern)) {
newFirst.push_back(i);
continue;
}
// If we're here, GEO_NEAR has a 2d index. We create a 2dgeonear plan with the
// entire tree as a filter, if possible.
GeoNear2DNode* solnRoot = new GeoNear2DNode();
solnRoot->nq = gnme->getData();
if (NULL != query.getProj()) {
solnRoot->addPointMeta = query.getProj()->wantGeoNearPoint();
solnRoot->addDistMeta = query.getProj()->wantGeoNearDistance();
}
if (MatchExpression::GEO_NEAR != query.root()->matchType()) {
// root is an AND, clone and delete the GEO_NEAR child.
MatchExpression* filterTree = query.root()->shallowClone();
verify(MatchExpression::AND == filterTree->matchType());
bool foundChild = false;
for (size_t i = 0; i < filterTree->numChildren(); ++i) {
if (MatchExpression::GEO_NEAR == filterTree->getChild(i)->matchType()) {
foundChild = true;
filterTree->getChildVector()->erase(filterTree->getChildVector()->begin() + i);
break;
}
}
verify(foundChild);
solnRoot->filter.reset(filterTree);
}
solnRoot->numWanted = query.getParsed().getNumToReturn();
if (0 == solnRoot->numWanted) {
solnRoot->numWanted = 100;
}
solnRoot->indexKeyPattern = relevantIndices[tag->first[i]].keyPattern;
// Remove the 2d index. 2d can only be the first field, and we know there is
// only one GEO_NEAR, so we don't care if anyone else was assigned it; it'll
// only be first for gnNode.
tag->first.erase(tag->first.begin() + i);
QuerySolution* soln = QueryPlannerAnalysis::analyzeDataAccess(query, params, solnRoot);
if (NULL != soln) {
out->push_back(soln);
}
}
// Continue planning w/non-2d indices tagged for this pred.
tag->first.swap(newFirst);
if (0 == tag->first.size() && 0 == tag->notFirst.size()) {