diff options
Diffstat (limited to 'src/mongo/db/pipeline/dependencies.cpp')
-rw-r--r-- | src/mongo/db/pipeline/dependencies.cpp | 224 |
1 files changed, 113 insertions, 111 deletions
diff --git a/src/mongo/db/pipeline/dependencies.cpp b/src/mongo/db/pipeline/dependencies.cpp index 128d46bd703..30ced50e06a 100644 --- a/src/mongo/db/pipeline/dependencies.cpp +++ b/src/mongo/db/pipeline/dependencies.cpp @@ -35,146 +35,148 @@ namespace mongo { - using std::set; - using std::string; - using std::vector; +using std::set; +using std::string; +using std::vector; - namespace str = mongoutils::str; +namespace str = mongoutils::str; - BSONObj DepsTracker::toProjection() const { - BSONObjBuilder bb; +BSONObj DepsTracker::toProjection() const { + BSONObjBuilder bb; - if (needTextScore) - bb.append(Document::metaFieldTextScore, BSON("$meta" << "textScore")); + if (needTextScore) + bb.append(Document::metaFieldTextScore, + BSON("$meta" + << "textScore")); - if (needWholeDocument) - return bb.obj(); + if (needWholeDocument) + return bb.obj(); - if (fields.empty()) { - // Projection language lacks good a way to say no fields needed. This fakes it. - bb.append("_id", 0); - bb.append("$noFieldsNeeded", 1); - return bb.obj(); - } + if (fields.empty()) { + // Projection language lacks good a way to say no fields needed. This fakes it. + bb.append("_id", 0); + bb.append("$noFieldsNeeded", 1); + return bb.obj(); + } - bool needId = false; - string last; - for (set<string>::const_iterator it(fields.begin()), end(fields.end()); it!=end; ++it) { - if (str::startsWith(*it, "_id") && (it->size() == 3 || (*it)[3] == '.')) { - // _id and subfields are handled specially due in part to SERVER-7502 - needId = true; - continue; - } - - if (!last.empty() && str::startsWith(*it, last)) { - // we are including a parent of *it so we don't need to include this field - // explicitly. In fact, due to SERVER-6527 if we included this field, the parent - // wouldn't be fully included. This logic relies on on set iterators going in - // lexicographic order so that a string is always directly before of all fields it - // prefixes. - continue; - } - - last = *it + '.'; - bb.append(*it, 1); + bool needId = false; + string last; + for (set<string>::const_iterator it(fields.begin()), end(fields.end()); it != end; ++it) { + if (str::startsWith(*it, "_id") && (it->size() == 3 || (*it)[3] == '.')) { + // _id and subfields are handled specially due in part to SERVER-7502 + needId = true; + continue; } - if (needId) // we are explicit either way - bb.append("_id", 1); - else - bb.append("_id", 0); + if (!last.empty() && str::startsWith(*it, last)) { + // we are including a parent of *it so we don't need to include this field + // explicitly. In fact, due to SERVER-6527 if we included this field, the parent + // wouldn't be fully included. This logic relies on on set iterators going in + // lexicographic order so that a string is always directly before of all fields it + // prefixes. + continue; + } - return bb.obj(); + last = *it + '.'; + bb.append(*it, 1); } - // ParsedDeps::_fields is a simple recursive look-up table. For each field: - // If the value has type==Bool, the whole field is needed - // If the value has type==Object, the fields in the subobject are needed - // All other fields should be missing which means not needed - boost::optional<ParsedDeps> DepsTracker::toParsedDeps() const { - MutableDocument md; + if (needId) // we are explicit either way + bb.append("_id", 1); + else + bb.append("_id", 0); - if (needWholeDocument || needTextScore) { - // can't use ParsedDeps in this case - return boost::none; - } + return bb.obj(); +} - string last; - for (set<string>::const_iterator it(fields.begin()), end(fields.end()); it!=end; ++it) { - if (!last.empty() && str::startsWith(*it, last)) { - // we are including a parent of *it so we don't need to include this field - // explicitly. In fact, if we included this field, the parent wouldn't be fully - // included. This logic relies on on set iterators going in lexicographic order so - // that a string is always directly before of all fields it prefixes. - continue; - } - last = *it + '.'; - md.setNestedField(*it, Value(true)); - } +// ParsedDeps::_fields is a simple recursive look-up table. For each field: +// If the value has type==Bool, the whole field is needed +// If the value has type==Object, the fields in the subobject are needed +// All other fields should be missing which means not needed +boost::optional<ParsedDeps> DepsTracker::toParsedDeps() const { + MutableDocument md; + + if (needWholeDocument || needTextScore) { + // can't use ParsedDeps in this case + return boost::none; + } - return ParsedDeps(md.freeze()); + string last; + for (set<string>::const_iterator it(fields.begin()), end(fields.end()); it != end; ++it) { + if (!last.empty() && str::startsWith(*it, last)) { + // we are including a parent of *it so we don't need to include this field + // explicitly. In fact, if we included this field, the parent wouldn't be fully + // included. This logic relies on on set iterators going in lexicographic order so + // that a string is always directly before of all fields it prefixes. + continue; + } + last = *it + '.'; + md.setNestedField(*it, Value(true)); } + return ParsedDeps(md.freeze()); +} + namespace { - // Mutually recursive with arrayHelper - Document documentHelper(const BSONObj& bson, const Document& neededFields); - - // Handles array-typed values for ParsedDeps::extractFields - Value arrayHelper(const BSONObj& bson, const Document& neededFields) { - BSONObjIterator it(bson); - - vector<Value> values; - while (it.more()) { - BSONElement bsonElement(it.next()); - if (bsonElement.type() == Object) { - Document sub = documentHelper(bsonElement.embeddedObject(), neededFields); - values.push_back(Value(sub)); - } - - if (bsonElement.type() == Array) { - values.push_back(arrayHelper(bsonElement.embeddedObject(), neededFields)); - } +// Mutually recursive with arrayHelper +Document documentHelper(const BSONObj& bson, const Document& neededFields); + +// Handles array-typed values for ParsedDeps::extractFields +Value arrayHelper(const BSONObj& bson, const Document& neededFields) { + BSONObjIterator it(bson); + + vector<Value> values; + while (it.more()) { + BSONElement bsonElement(it.next()); + if (bsonElement.type() == Object) { + Document sub = documentHelper(bsonElement.embeddedObject(), neededFields); + values.push_back(Value(sub)); } - return Value(std::move(values)); + if (bsonElement.type() == Array) { + values.push_back(arrayHelper(bsonElement.embeddedObject(), neededFields)); + } } - // Handles object-typed values including the top-level for ParsedDeps::extractFields - Document documentHelper(const BSONObj& bson, const Document& neededFields) { - MutableDocument md(neededFields.size()); + return Value(std::move(values)); +} - BSONObjIterator it(bson); - while (it.more()) { - BSONElement bsonElement (it.next()); - StringData fieldName = bsonElement.fieldNameStringData(); - Value isNeeded = neededFields[fieldName]; +// Handles object-typed values including the top-level for ParsedDeps::extractFields +Document documentHelper(const BSONObj& bson, const Document& neededFields) { + MutableDocument md(neededFields.size()); - if (isNeeded.missing()) - continue; + BSONObjIterator it(bson); + while (it.more()) { + BSONElement bsonElement(it.next()); + StringData fieldName = bsonElement.fieldNameStringData(); + Value isNeeded = neededFields[fieldName]; - if (isNeeded.getType() == Bool) { - md.addField(fieldName, Value(bsonElement)); - continue; - } + if (isNeeded.missing()) + continue; - dassert(isNeeded.getType() == Object); + if (isNeeded.getType() == Bool) { + md.addField(fieldName, Value(bsonElement)); + continue; + } - if (bsonElement.type() == Object) { - Document sub = documentHelper(bsonElement.embeddedObject(), isNeeded.getDocument()); - md.addField(fieldName, Value(sub)); - } + dassert(isNeeded.getType() == Object); - if (bsonElement.type() == Array) { - md.addField(fieldName, arrayHelper(bsonElement.embeddedObject(), - isNeeded.getDocument())); - } + if (bsonElement.type() == Object) { + Document sub = documentHelper(bsonElement.embeddedObject(), isNeeded.getDocument()); + md.addField(fieldName, Value(sub)); } - return md.freeze(); + if (bsonElement.type() == Array) { + md.addField(fieldName, + arrayHelper(bsonElement.embeddedObject(), isNeeded.getDocument())); + } } -} // namespace - Document ParsedDeps::extractFields(const BSONObj& input) const { - return documentHelper(input, _fields); - } + return md.freeze(); +} +} // namespace + +Document ParsedDeps::extractFields(const BSONObj& input) const { + return documentHelper(input, _fields); +} } |