diff options
author | Benjamin Murphy <benjamin_murphy@me.com> | 2016-04-26 18:20:37 -0400 |
---|---|---|
committer | Benjamin Murphy <benjamin_murphy@me.com> | 2016-04-29 12:15:31 -0400 |
commit | c1814956391a9c37f4f4e6cca93c08f7fcacc85d (patch) | |
tree | 886345f943a127852bce0a31bf8a5bfab0a9a3bc /src/mongo/db/pipeline/document_source_lookup.cpp | |
parent | 18802c0618405df6ebc4bc0c4ac7eb3d82d00f07 (diff) | |
download | mongo-c1814956391a9c37f4f4e6cca93c08f7fcacc85d.tar.gz |
SERVER-23922 Lookup correctly serializes an internalized match.
Diffstat (limited to 'src/mongo/db/pipeline/document_source_lookup.cpp')
-rw-r--r-- | src/mongo/db/pipeline/document_source_lookup.cpp | 68 |
1 files changed, 44 insertions, 24 deletions
diff --git a/src/mongo/db/pipeline/document_source_lookup.cpp b/src/mongo/db/pipeline/document_source_lookup.cpp index 611660eb479..a3e7f29ec77 100644 --- a/src/mongo/db/pipeline/document_source_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_lookup.cpp @@ -90,6 +90,14 @@ boost::optional<Document> DocumentSourceLookUp::getNext() { uassert(4567, "from collection cannot be sharded", !_mongod->isSharded(_fromNs)); + if (!_additionalFilter && _matchSrc) { + // We have internalized a $match, but have not yet computed the descended $match that should + // be applied to our queries. + _additionalFilter = DocumentSourceMatch::descendMatchOnPath(_matchSrc->getMatchExpression(), + _as.getPath(false), + pExpCtx)->getQuery(); + } + if (_handlingUnwind) { return unwindResult(); } @@ -98,8 +106,11 @@ boost::optional<Document> DocumentSourceLookUp::getNext() { if (!input) return {}; - BSONObj filter = _matchSrc ? _matchSrc->getQuery() : BSONObj(); - BSONObj query = queryForInput(*input, _localField, _foreignFieldFieldName, filter); + // If we have not absorbed a $unwind, we cannot absorb a $match. If we have absorbed a $unwind, + // '_handlingUnwind' would be set to true, and we would not have made it here. + invariant(!_matchSrc); + + BSONObj query = queryForInput(*input, _localField, _foreignFieldFieldName, BSONObj()); std::unique_ptr<DBClientCursor> cursor = _mongod->directClient()->query(_fromNs.ns(), query); std::vector<Value> results; @@ -242,14 +253,11 @@ Pipeline::SourceContainer::iterator DocumentSourceLookUp::optimizeAt( // We can internalize the entire $match. if (!_handlingMatch) { - _matchSrc = DocumentSourceMatch::descendMatchOnPath( - dependent->getMatchExpression(), outputPath, pExpCtx); + _matchSrc = dependent; _handlingMatch = true; } else { // We have already absorbed a $match. We need to join it with 'dependent'. - auto descended = DocumentSourceMatch::descendMatchOnPath( - dependent->getMatchExpression(), outputPath, pExpCtx); - _matchSrc->joinMatchWith(descended); + _matchSrc->joinMatchWith(dependent); } return locationOfNextPossibleOptimization; } @@ -355,7 +363,7 @@ boost::optional<Document> DocumentSourceLookUp::unwindResult() { if (!_input) return {}; - BSONObj filter = _matchSrc ? _matchSrc->getQuery() : BSONObj(); + BSONObj filter = _additionalFilter.value_or(BSONObj()); _cursor = _mongod->directClient()->query( _fromNs.ns(), DocumentSourceLookUp::queryForInput( @@ -395,25 +403,37 @@ void DocumentSourceLookUp::serializeToArray(std::vector<Value>& array, bool expl DOC(getSourceName() << DOC("from" << _fromNs.coll() << "as" << _as.getPath(false) << "localField" << _localField.getPath(false) << "foreignField" << _foreignField.getPath(false)))); - if (_handlingUnwind && explain) { - const boost::optional<FieldPath> indexPath = _unwindSrc->indexPath(); - output[getSourceName()]["unwinding"] = - Value(DOC("preserveNullAndEmptyArrays" - << _unwindSrc->preserveNullAndEmptyArrays() << "includeArrayIndex" - << (indexPath ? Value((*indexPath).getPath(false)) : Value()))); - } + if (explain) { + if (_handlingUnwind) { + const boost::optional<FieldPath> indexPath = _unwindSrc->indexPath(); + output[getSourceName()]["unwinding"] = + Value(DOC("preserveNullAndEmptyArrays" + << _unwindSrc->preserveNullAndEmptyArrays() << "includeArrayIndex" + << (indexPath ? Value(indexPath->getPath(false)) : Value()))); + } - if (_matchSrc && explain) { - output[getSourceName()]["matching"] = Value(_matchSrc->getQuery()); - } + if (_matchSrc) { + // Our output does not have to be parseable, so include a "matching" field with the + // descended match expression. + output[getSourceName()]["matching"] = Value( + DocumentSourceMatch::descendMatchOnPath( + _matchSrc->getMatchExpression(), _as.getPath(false), pExpCtx)->getQuery()); + } - array.push_back(Value(output.freeze())); - if (_handlingUnwind && !explain) { - _unwindSrc->serializeToArray(array); - } + array.push_back(Value(output.freeze())); + } else { + array.push_back(Value(output.freeze())); - if (_matchSrc && !explain) { - _matchSrc->serializeToArray(array); + if (_handlingUnwind) { + _unwindSrc->serializeToArray(array); + } + + if (_matchSrc) { + // '_matchSrc' tracks the originally specified $match. We descend upon the $match in the + // first call to getNext(), at which point we are confident that we no longer need to + // serialize the $lookup again. + _matchSrc->serializeToArray(array); + } } } |