mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Support subsets fields filtering.
Rewrote the returned closure. Still don't support '$' and '$slice' operators.
This commit is contained in:
@@ -623,7 +623,7 @@ LocalCollection.prototype._modifyAndNotify = function (
|
||||
// in the output. So it's safe to skip recompute if neither before or
|
||||
// after are true.)
|
||||
if (before || after)
|
||||
recomputeQids[qid] = true;
|
||||
recomputeQids[qid] = true;
|
||||
} else if (before && !after) {
|
||||
LocalCollection._removeFromResults(query, doc);
|
||||
} else if (!before && after) {
|
||||
@@ -1069,7 +1069,7 @@ LocalCollection._compileProjection = function (fields) {
|
||||
var _idProjection = _.isUndefined(fields._id) ? true : fields._id;
|
||||
delete fields._id;
|
||||
var including = null; // Unknown
|
||||
var projectionRules = [];
|
||||
var projectionRulesTree = {}; // Tree represented as nested objects
|
||||
|
||||
_.each(fields, function (rule, keyPath) {
|
||||
rule = !!rule;
|
||||
@@ -1078,74 +1078,47 @@ LocalCollection._compileProjection = function (fields) {
|
||||
if (including !== rule)
|
||||
// This error message is copies from MongoDB shell
|
||||
throw MinimongoError("You cannot currently mix including and excluding fields.");
|
||||
projectionRules.push(keyPath.split('.'));
|
||||
var treePos = projectionRulesTree;
|
||||
keyPath = keyPath.split('.');
|
||||
|
||||
_.each(keyPath.slice(0, -1), function (key) {
|
||||
if (!_.has(treePos, key))
|
||||
treePos[key] = {};
|
||||
treePos = treePos[key];
|
||||
});
|
||||
|
||||
treePos[_.last(keyPath)] = including;
|
||||
});
|
||||
|
||||
// XXX do these functions share too much in common?
|
||||
if (including)
|
||||
return function (doc) {
|
||||
var result = {};
|
||||
// returns transformed doc according to ruleTree
|
||||
var transform = function (doc, ruleTree) {
|
||||
var res = including ? {} : EJSON.clone(doc);
|
||||
_.each(ruleTree, function (rule, key) {
|
||||
if (!_.has(doc, key))
|
||||
return;
|
||||
if (_.isObject(rule)) {
|
||||
if (_.isArray(doc[key]))
|
||||
res[key] = _.map(doc[key], function (subdoc) {
|
||||
return transform(subdoc, rule);
|
||||
});
|
||||
else if (_.isObject(doc[key]))
|
||||
res[key] = transform(doc[key], rule);
|
||||
} else if (including)
|
||||
res[key] = doc[key];
|
||||
else
|
||||
delete res[key];
|
||||
});
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
_.each(projectionRules, function (keyPath) {
|
||||
var target = result;
|
||||
var docTarget = doc;
|
||||
for (var i = 0; i < keyPath.length - 1; i++) {
|
||||
var key = keyPath[i];
|
||||
// This block simulates MongoDB behavior for different edge-cases when
|
||||
// object on certain path wasn't found or array found instead of an
|
||||
// object, or vice-versa.
|
||||
if (!_.has(target, key)) {
|
||||
if (_.isArray(docTarget[key])) {
|
||||
target[key] = [];
|
||||
docTarget = undefined;
|
||||
break;
|
||||
} else if (_.isObject(docTarget[key]))
|
||||
target[key] = {};
|
||||
else {
|
||||
docTarget = undefined;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
target = target[key];
|
||||
docTarget = docTarget[key];
|
||||
}
|
||||
|
||||
if (keyPath.length > 0 && docTarget && _.has(docTarget, _.last(keyPath)))
|
||||
target[_.last(keyPath)] = docTarget[_.last(keyPath)];
|
||||
});
|
||||
|
||||
if (_idProjection && _.has(doc, '_id'))
|
||||
result._id = doc._id;
|
||||
|
||||
return result;
|
||||
};
|
||||
else
|
||||
return function (doc) {
|
||||
// XXX Deep copy on this level might be a slowing factor,
|
||||
// In fact we need it only in case of nested excluded fields.
|
||||
var result = EJSON.clone(doc);
|
||||
|
||||
_.each(projectionRules, function (keyPath) {
|
||||
var target = result;
|
||||
var docTarget = doc;
|
||||
for (var i = 0; i < keyPath.length - 1; i++) {
|
||||
var key = keyPath[i];
|
||||
if (!_.has(target, key)) {
|
||||
break;
|
||||
}
|
||||
|
||||
target = target[key];
|
||||
docTarget = docTarget[key];
|
||||
}
|
||||
|
||||
if (keyPath.length > 0)
|
||||
delete target[_.last(keyPath)];
|
||||
});
|
||||
|
||||
if (!_idProjection)
|
||||
delete result._id;
|
||||
|
||||
return result;
|
||||
};
|
||||
return function (obj) {
|
||||
var res = transform(obj, projectionRulesTree);
|
||||
|
||||
if (_idProjection && _.has(obj, '_id'))
|
||||
res._id = obj._id;
|
||||
if (!_idProjection && _.has(res, '_id'))
|
||||
delete res._id;
|
||||
return res;
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user