function getSingleFieldCoreQueryPlan(selector, index) { var field = getKey(index.def.fields[0]); //ignoring this because the test to exercise the branch is skipped at the moment /* istanbul ignore next */ var matcher = selector[field] || {}; var inMemoryFields = []; var userOperators = Object.keys(matcher); var combinedOpts; userOperators.forEach(function (userOperator) { if (isNonLogicalMatcher(userOperator)) { inMemoryFields.push(field); return; } var userValue = matcher[userOperator]; var newQueryOpts = getSingleFieldQueryOptsFor(userOperator, userValue); if (combinedOpts) { combinedOpts = mergeObjects([combinedOpts, newQueryOpts]); } else { combinedOpts = newQueryOpts; } }); return { queryOpts: combinedOpts, inMemoryFields: inMemoryFields }; }
// check all the index fields for usages of '$ne' // e.g. if the user queries {foo: {$ne: 'foo'}, bar: {$eq: 'bar'}}, // then we can neither use an index on ['foo'] nor an index on // ['foo', 'bar'], but we can use an index on ['bar'] or ['bar', 'foo'] function checkFieldsLogicallySound(indexFields, selector) { var firstField = indexFields[0]; var matcher = selector[firstField]; if (typeof matcher === 'undefined') { return true; } var hasLogicalOperator = Object.keys(matcher).some(function (matcherKey) { return !(isNonLogicalMatcher(matcherKey)); }); if (!hasLogicalOperator) { return false; } var isInvalidNe = Object.keys(matcher).length === 1 && getKey(matcher) === '$ne'; return !isInvalidNe; }
// so when you do e.g. $eq/$eq, we can do it entirely in the database. // but when you do e.g. $gt/$eq, the first part can be done // in the database, but the second part has to be done in-memory, // because $gt has forced us to lose precision. // so that's what this determines function userOperatorLosesPrecision(selector, field) { var matcher = selector[field]; var userOperator = getKey(matcher); return userOperator !== '$eq'; }