{"record":{"id":"8b45cc1812a82314","repo":"meteor/meteor","slug":"or-and-nor-entries-need-to-be-full-objects","errorCode":null,"errorMessage":"$or/$and/$nor entries need to be full objects","messagePattern":"\\$or/\\$and/\\$nor entries need to be full objects","errorType":"exception","errorClass":"MiniMongoQueryError","httpStatus":null,"severity":"error","filePath":"packages/minimongo/common.js","lineNumber":561,"sourceCode":"      delete match.distance;\n      delete match.arrayIndices;\n    }\n\n    return match;\n  };\n}\n\nconst andDocumentMatchers = andSomeMatchers;\nconst andBranchedMatchers = andSomeMatchers;\n\nfunction compileArrayOfDocumentSelectors(selectors, matcher, inElemMatch) {\n  if (!Array.isArray(selectors) || selectors.length === 0) {\n    throw new MiniMongoQueryError('$and/$or/$nor must be nonempty array');\n  }\n\n  return selectors.map(subSelector => {\n    if (!LocalCollection._isPlainObject(subSelector)) {\n      throw new MiniMongoQueryError('$or/$and/$nor entries need to be full objects');\n    }\n\n    return compileDocumentSelector(subSelector, matcher, {inElemMatch});\n  });\n}\n\n// Takes in a selector that could match a full document (eg, the original\n// selector). Returns a function mapping document->result object.\n//\n// matcher is the Matcher object we are compiling.\n//\n// If this is the root document selector (ie, not wrapped in $and or the like),\n// then isRoot is true. (This is used by $near.)\nexport function compileDocumentSelector(docSelector, matcher, options = {}) {\n  const docMatchers = Object.keys(docSelector).map(key => {\n    const subSelector = docSelector[key];\n\n    if (key.substr(0, 1) === '$') {","sourceCodeStart":543,"sourceCodeEnd":579,"githubUrl":"https://github.com/meteor/meteor/blob/5076d2f818d3cac01d0cf8312fa5b2332076a4fb/packages/minimongo/common.js#L543-L579","documentation":"Each element of an $and/$or/$nor array must itself be a full document selector (a plain object), checked with LocalCollection._isPlainObject. This guards the .map in compileArrayOfDocumentSelectors, ensuring each branch is a valid sub-selector rather than a scalar, array, or class instance. MongoDB applies the same rule: every array entry is interpreted as a separate query document.","triggerScenarios":"Passing {$or: [1, 2]}, {$or: ['foo']}, {$and: [{a:1}, [1,2]]}, or an array containing a Date / ObjectId / EJSON-serialized value that is not a plain object.","commonSituations":"Spreading a mixed list into $or where some entries are raw ids instead of {_id: id} objects, or de-serializing a selector whose array elements lost their plain-object prototype.","solutions":["Wrap each scalar entry as a document: map ids to {_id: id} before $or.","Validate with selectors.every(s => LocalCollection._isPlainObject(s)) before querying.","Re-check the shape of any selector coming from JSON.parse or an EJSON payload."],"exampleFix":"// before\ndb.find({ $or: idList });\n// after\ndb.find({ $or: idList.map(id => ({ _id: id })) });","handlingStrategy":"validation","validationCode":"function normalizeOr(items) {\n  if (!items.every(x => x && typeof x === 'object' && !Array.isArray(x))) {\n    throw new TypeError('$or entries must be plain objects');\n  }\n  return items;\n}\ndb.find({ $or: normalizeOr(rawList) });","typeGuard":"function isPlainObjectList(arr) {\n  return Array.isArray(arr) && arr.every(\n    x => x !== null && Object.getPrototypeOf(x) === Object.prototype);\n}","tryCatchPattern":null,"preventionTips":["Always wrap raw ids as {_id: id} before placing in $or.","Validate selector shape with a schema (e.g. ajv) in API boundaries.","Avoid passing class instances (Date, ObjectId wrappers) directly into selector arrays."],"tags":["minimongo","query","selector","logical-operator","type"],"backgroundTag":null,"analyzedSha":"5076d2f818d3cac01d0cf8312fa5b2332076a4fb","analyzedAt":"2026-08-13T03:27:40.142Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}