|
@@ -3,14 +3,16 @@ var MatchDocumentSource = module.exports = (function(){
|
|
|
// CONSTRUCTOR
|
|
|
/**
|
|
|
* A match document source built off of FilterBaseDocumentSource
|
|
|
- * Currently uses sift to fake it
|
|
|
- *
|
|
|
+ *
|
|
|
+ * NOTE: THIS IS A DEVIATION FROM THE MONGO IMPLEMENTATION.
|
|
|
+ * TODO: internally uses `sift` to fake it, which has bugs, so we need to reimplement this by porting the MongoDB implementation
|
|
|
+ *
|
|
|
* @class MatchDocumentSource
|
|
|
- * @namespace munge.pipeline.documentsource
|
|
|
- * @module munge
|
|
|
+ * @namespace mungedb-aggregate.pipeline.documentSources
|
|
|
+ * @module mungedb-aggregate
|
|
|
* @constructor
|
|
|
* @param {Object} query the match query to use
|
|
|
- **/
|
|
|
+ **/
|
|
|
var klass = module.exports = MatchDocumentSource = function MatchDocumentSource(query /*, pCtx*/){
|
|
|
if(arguments.length !== 1) throw new Error("one arg expected");
|
|
|
base.call(this);
|
|
@@ -18,69 +20,24 @@ var MatchDocumentSource = module.exports = (function(){
|
|
|
this.matcher = sift(query);
|
|
|
}, base = require('./FilterBaseDocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
|
|
|
|
|
|
- klass.extend = function extend(obj, withObj){
|
|
|
- var args = Array.prototype.slice.call(arguments), lastArg = args[args.length - 1];
|
|
|
- for(var i = 1, n = args.length; i < n; i++){
|
|
|
- withObj = args[i];
|
|
|
- for(var key in withObj){
|
|
|
- if(withObj.hasOwnProperty(key)){
|
|
|
- var objVal = obj[key], withObjVal = withObj[key];
|
|
|
- if(objVal instanceof Object && withObjVal.constructor === Object){
|
|
|
- klass.extend(objVal, withObjVal);
|
|
|
- }else{
|
|
|
- obj[key] = withObjVal;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return obj;
|
|
|
- };
|
|
|
-
|
|
|
// DEPENDENCIES
|
|
|
- var sift = require("sift"),
|
|
|
- traverse = require("traverse");
|
|
|
+ var sift = require("sift");
|
|
|
|
|
|
klass.matchName = "$match";
|
|
|
proto.getSourceName = function getSourceName(){
|
|
|
return klass.matchName;
|
|
|
};
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
- * Adds dependencies to the contained ObjectExpression
|
|
|
- *
|
|
|
- * THIS IS A DEVIATION FROM THE MONGO IMPLEMENTATION.
|
|
|
- *
|
|
|
- * @param {deps} An object that is treated as a set of strings
|
|
|
- * @return A string that is part of the GetDepsReturn enum
|
|
|
- **/
|
|
|
- proto.getDependencies = function getDependencies(deps) {
|
|
|
- var tmpArr = [];
|
|
|
- // We need to construct a facets for both keys and values if they contain dotted paths
|
|
|
- traverse(this.query).forEach(function(value) {
|
|
|
- var key = this.key;
|
|
|
- if (typeof value == "string" && value[0] == "$") { // If we find a document path in the value
|
|
|
- tmpArr.push(value.replace(/^\$/, ""));
|
|
|
- } else if (key && /^[A-Za-z_]/.test(key)) { //if we find a non-operator as a key
|
|
|
- tmpArr.push(key);
|
|
|
- }
|
|
|
- });
|
|
|
- for (var i = 0; i < tmpArr.length; i++) {
|
|
|
- deps[tmpArr[i]] = 1;
|
|
|
- }
|
|
|
- return "SEE_NEXT";
|
|
|
- };
|
|
|
-
|
|
|
- /**
|
|
|
* Create an object that represents the document source. The object
|
|
|
- * will have a single field whose name is the source's name. This
|
|
|
- * will be used by the default implementation of addToJsonArray()
|
|
|
- * to add this object to a pipeline being represented in JSON.
|
|
|
- *
|
|
|
- * @method sourceToJson
|
|
|
- * @param {Object} builder JSONObjBuilder: a blank object builder to write to
|
|
|
- * @param {Boolean} explain create explain output
|
|
|
- **/
|
|
|
+ * will have a single field whose name is the source's name. This
|
|
|
+ * will be used by the default implementation of addToJsonArray()
|
|
|
+ * to add this object to a pipeline being represented in JSON.
|
|
|
+ *
|
|
|
+ * @method sourceToJson
|
|
|
+ * @param {Object} builder JSONObjBuilder: a blank object builder to write to
|
|
|
+ * @param {Boolean} explain create explain output
|
|
|
+ **/
|
|
|
proto.sourceToJson = function sourceToJson(builder, explain) {
|
|
|
builder[this.getSourceName()] = this.matcher.query;
|
|
|
};
|
|
@@ -119,7 +76,10 @@ var MatchDocumentSource = module.exports = (function(){
|
|
|
* @param builder the builder to write to
|
|
|
**/
|
|
|
proto.toMatcherJson = function toMatcherJson(builder) {
|
|
|
- klass.extend(builder, this.matcher.query);
|
|
|
+ var q = this.matcher.query;
|
|
|
+ for(var k in q){
|
|
|
+ builder[k] = q[k];
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
klass.uassertNoDisallowedClauses = function uassertNoDisallowedClauses(query) {
|
|
@@ -131,20 +91,15 @@ var MatchDocumentSource = module.exports = (function(){
|
|
|
if ( query[key] == "$near") throw new Error("code 16424; $near is not allowed inside of a $match aggregation expression");
|
|
|
if ( query[key] == "$within") throw new Error("code 16425l $within is not allowed inside of a $match aggregation expression");
|
|
|
if ( query[key] == "$nearSphere") throw new Error("code 16426; $nearSphere is not allowed inside of a $match aggregation expression");
|
|
|
-
|
|
|
- if(query[key] instanceof Object && query[key].constructor === Object)
|
|
|
- this.uassertNoDisallowedClauses(query[key]);
|
|
|
+ if(query[key] instanceof Object && query[key].constructor === Object) this.uassertNoDisallowedClauses(query[key]);
|
|
|
}
|
|
|
}
|
|
|
- };
|
|
|
+ };
|
|
|
|
|
|
klass.createFromJson = function createFromJson(JsonElement) {
|
|
|
if (!(JsonElement instanceof Object) || JsonElement.constructor !== Object) throw new Error("code 15959 ; the match filter must be an expression in an object");
|
|
|
-
|
|
|
klass.uassertNoDisallowedClauses(JsonElement);
|
|
|
-
|
|
|
var matcher = new MatchDocumentSource(JsonElement);
|
|
|
-
|
|
|
return matcher;
|
|
|
};
|
|
|
|