| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- "use strict";
- /**
- * Allows components in an aggregation pipeline to report what they need from their input.
- *
- * @class DepsTracker
- * @namespace mungedb-aggregate.pipeline
- * @module mungedb-aggregate
- * @constructor
- */
- var DepsTracker = module.exports = function DepsTracker() {
- /* fields is a set of strings */
- this.fields = {};
- this.needWholeDocument = false;
- this.needTextScore = false;
- }, klass = DepsTracker, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
- var ParsedDeps = require("./ParsedDeps");
- /**
- * Returns a projection object covering the dependencies tracked by this class.
- *
- * @method toProjection
- * @return {Object} projection of caller's dependencies
- */
- proto.toProjection = function toProjection() {
- var proj = {};
- // if(this.needTextScore) {
- // bb.append(Document::metaFieldTextScore, BSON("$meta" << "textScore"));
- // }
- if (this.needWholeDocument) {
- return proj;
- }
- if (Object.keys(this.fields).length === 0) {
- // Projection language lacks good a way to say no fields needed. This fakes it.
- proj._id = 0;
- proj.$noFieldsNeeded = 1;
- return proj;
- }
- var last = "",
- needId = false;
- Object.keys(this.fields).sort().forEach(function (it) {
- if (it.slice(0,3) == "_id" && (it.length == 3 || it.charAt(3) == ".")) {
- // _id and subfields are handled specially due in part to SERVER-7502
- needId = true;
- return;
- }
- if (last !== "" && it.slice(0, last.length) === 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.
- return;
- }
- last = it + ".";
- proj[it] = 1;
- });
- if (needId)
- proj._id = 1;
- else
- proj._id = 0;
- return proj;
- };
- /**
- * Takes a depsTracker and builds a simple recursive lookup table out of it.
- *
- * @method toParsedDeps
- * @return {ParsedDeps}
- */
- proto.toParsedDeps = function toParsedDeps() {
- var doc = {};
- if(this.needWholeDocument || this.needTextScore) {
- // can't use ParsedDeps in this case
- // TODO: not sure what appropriate equivalent to boost::none is
- return;
- }
- var last = "";
- Object.keys(this.fields).sort().forEach(function (it) {
- if (last !== "" && it.slice(0, last.length) === 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.
- return;
- }
- last = it + ".";
- // TODO: set nested field to true; i.e. a.b.c = true, not a = true
- doc[it] = true;
- });
- return new ParsedDeps(doc);
- };
|