bool BSONElementIterator::more() { if (subCursorHasMore()) { return true; } if (!_next.element().eoo()) { return true; } if (_state == DONE) { return false; } if (_state == BEGIN) { if (_traversalStart.type() != Array) { _next.reset(_traversalStart, BSONElement()); _state = DONE; return true; } // It's an array. _arrayIterationState.reset(_path->fieldRef(), _traversalStartIndex + 1); if (_arrayIterationState.hasMore && _path->nonLeafArrayBehavior() != ElementPath::NonLeafArrayBehavior::kTraverse) { // Don't allow traversing the array. if (_path->nonLeafArrayBehavior() == ElementPath::NonLeafArrayBehavior::kMatchSubpath) { _next.reset(_traversalStart, BSONElement()); _state = DONE; return true; } _state = DONE; return false; } else if (!_arrayIterationState.hasMore && _path->leafArrayBehavior() == ElementPath::LeafArrayBehavior::kNoTraversal) { // Return the leaf array. _next.reset(_traversalStart, BSONElement()); _state = DONE; return true; } _arrayIterationState.startIterator(_traversalStart); _state = IN_ARRAY; invariant(_next.element().eoo()); } if (_state == IN_ARRAY) { // We're traversing an array. Look at each array element. while (_arrayIterationState.more()) { BSONElement eltInArray = _arrayIterationState.next(); if (!_arrayIterationState.hasMore) { // Our path terminates at this array. _next should point at the current array // element. _next.reset(eltInArray, eltInArray); return true; } // Our path does not terminate at this array; there's a subpath left over. Inspect // the current array element to see if it could match the subpath. if (eltInArray.type() == Object) { // The current array element is a subdocument. See if the subdocument generates // any elements matching the remaining subpath. _subCursorPath.reset(new ElementPath()); _subCursorPath->init(_arrayIterationState.restOfPath); _subCursorPath->setLeafArrayBehavior(_path->leafArrayBehavior()); _subCursor.reset(new BSONElementIterator(_subCursorPath.get(), eltInArray.Obj())); if (subCursorHasMore()) { return true; } } else if (_arrayIterationState.isArrayOffsetMatch(eltInArray.fieldName())) { // The path we're traversing has an array offset component, and the current // array element corresponds to the offset we're looking for (for example: our // path has a ".0" component, and we're looking at the first element of the // array, so we should look inside this element). if (_arrayIterationState.nextEntireRest()) { // Our path terminates at the array offset. _next should point at the // current array element. _next._arrayOffset should be EOO, since this is not an // implicit array traversal. _next.reset(eltInArray, BSONElement()); return true; } invariant(eltInArray.type() != Object); // Handled above. if (eltInArray.type() == Array) { // The current array element is itself an array. See if the nested array // has any elements matching the remainihng. _subCursorPath.reset(new ElementPath()); _subCursorPath->init(_arrayIterationState.restOfPath.substr( _arrayIterationState.nextPieceOfPath.size() + 1)); _subCursorPath->setLeafArrayBehavior(_path->leafArrayBehavior()); BSONElementIterator* real = new BSONElementIterator( _subCursorPath.get(), _arrayIterationState._current.Obj()); _subCursor.reset(real); real->_arrayIterationState.reset(_subCursorPath->fieldRef(), 0); real->_arrayIterationState.startIterator(eltInArray); real->_state = IN_ARRAY; // Set _arrayIterationState._current to EOO. This is not an implicit array // traversal, so we should not override the array offset of the subcursor with // the current array offset. _arrayIterationState._current = BSONElement(); if (subCursorHasMore()) { return true; } } } } if (_arrayIterationState.hasMore) { return false; } _next.reset(_arrayIterationState._theArray, BSONElement()); _state = DONE; return true; } return false; }
bool BSONElementIterator::more() { if (subCursorHasMore()) { return true; } if (!_next.element().eoo()) { return true; } if (_state == DONE) { return false; } if (_state == BEGIN) { size_t idxPath = 0; BSONElement e = getFieldDottedOrArray(_context, _path->fieldRef(), &idxPath); if (e.type() != Array) { _next.reset(e, BSONElement(), false); _state = DONE; return true; } // It's an array. _arrayIterationState.reset(_path->fieldRef(), idxPath + 1); if (_arrayIterationState.hasMore && !_path->shouldTraverseNonleafArrays()) { // Don't allow traversing the array. _state = DONE; return false; } else if (!_arrayIterationState.hasMore && !_path->shouldTraverseLeafArray()) { // Return the leaf array. _next.reset(e, BSONElement(), true); _state = DONE; return true; } _arrayIterationState.startIterator(e); _state = IN_ARRAY; invariant(_next.element().eoo()); } if (_state == IN_ARRAY) { // We're traversing an array. Look at each array element. while (_arrayIterationState.more()) { BSONElement eltInArray = _arrayIterationState.next(); if (!_arrayIterationState.hasMore) { // Our path terminates at this array. _next should point at the current array // element. _next.reset(eltInArray, eltInArray, false); return true; } // Our path does not terminate at this array; there's a subpath left over. Inspect // the current array element to see if it could match the subpath. if (eltInArray.type() == Object) { // The current array element is a subdocument. See if the subdocument generates // any elements matching the remaining subpath. _subCursorPath.reset(new ElementPath()); _subCursorPath->init(_arrayIterationState.restOfPath); _subCursorPath->setTraverseLeafArray(_path->shouldTraverseLeafArray()); _subCursor.reset(new BSONElementIterator(_subCursorPath.get(), eltInArray.Obj())); if (subCursorHasMore()) { return true; } } else if (_arrayIterationState.isArrayOffsetMatch(eltInArray.fieldName())) { // The path we're traversing has an array offset component, and the current // array element corresponds to the offset we're looking for (for example: our // path has a ".0" component, and we're looking at the first element of the // array, so we should look inside this element). if (_arrayIterationState.nextEntireRest()) { // Our path terminates at the array offset. _next should point at the // current array element. _next.reset(eltInArray, eltInArray, false); return true; } invariant(eltInArray.type() != Object); // Handled above. if (eltInArray.type() == Array) { // The current array element is itself an array. See if the nested array // has any elements matching the remainihng. _subCursorPath.reset(new ElementPath()); _subCursorPath->init(_arrayIterationState.restOfPath.substr( _arrayIterationState.nextPieceOfPath.size() + 1)); _subCursorPath->setTraverseLeafArray(_path->shouldTraverseLeafArray()); BSONElementIterator* real = new BSONElementIterator( _subCursorPath.get(), _arrayIterationState._current.Obj()); _subCursor.reset(real); real->_arrayIterationState.reset(_subCursorPath->fieldRef(), 0); real->_arrayIterationState.startIterator(eltInArray); real->_state = IN_ARRAY; _arrayIterationState._current = BSONElement(); if (subCursorHasMore()) { return true; } } } } if (_arrayIterationState.hasMore) { return false; } _next.reset(_arrayIterationState._theArray, BSONElement(), true); _state = DONE; return true; } return false; }