Interval:: Interval() : _intervalData(BSONObj()) , start(BSONElement()) , startInclusive(false) , end(BSONElement()) , endInclusive(false) { }
ElementIterator::Context SimpleArrayElementIterator::next() { if (_iterator.more()) { Context e; e.reset(_iterator.next(), BSONElement()); return e; } _returnArrayLast = false; Context e; e.reset(_theArray, BSONElement()); return e; }
/** * @param arrayNestedArray - set if the returned element is an array nested directly within arr. */ BSONElement extractNextElement( const BSONObj &obj, const BSONObj &arr, const char *&field, bool &arrayNestedArray ) const { string firstField = mongoutils::str::before( field, '.' ); bool haveObjField = !obj.getField( firstField ).eoo(); BSONElement arrField = arr.getField( firstField ); bool haveArrField = !arrField.eoo(); // An index component field name cannot exist in both a document array and one of that array's children. uassert( 15855, mongoutils::str::stream() << "Ambiguous field name found in array (do not use numeric field names in " "embedded elements in an array), field: '" << arrField.fieldName() << "' for array: " << arr, !haveObjField || !haveArrField ); arrayNestedArray = false; if ( haveObjField ) { return obj.getFieldDottedOrArray( field ); } else if ( haveArrField ) { if ( arrField.type() == Array ) { arrayNestedArray = true; } return arr.getFieldDottedOrArray( field ); } return BSONElement(); }
INT32 _rtnSQLMax::result( BSONObjBuilder &builder ) { INT32 rc = SDB_OK ; try { if ( _ele.eoo() ) { builder.appendNull( _alias.toString() ) ; } else { builder.appendAs( _ele, _alias.toString() ) ; } _obj = BSONObj() ; _ele = BSONElement() ; } catch ( std::exception &e ) { PD_LOG( PDERROR, "unexcepted err happened:%s", e.what() ) ; rc = SDB_SYS ; goto error ; } done: return rc ; error: goto done ; }
BSONElement BtreeKeyGeneratorV1::extractNextElement(const BSONObj& obj, const PositionalPathInfo& positionalInfo, const char** field, bool* arrayNestedArray) const { std::string firstField = mongoutils::str::before(*field, '.'); bool haveObjField = !obj.getField(firstField).eoo(); BSONElement arrField = positionalInfo.positionallyIndexedElt; // An index component field name cannot exist in both a document // array and one of that array's children. uassert(16746, mongoutils::str::stream() << "Ambiguous field name found in array (do not use numeric field names in " "embedded elements in an array), field: '" << arrField.fieldName() << "' for array: " << positionalInfo.arrayObj, !haveObjField || !positionalInfo.hasPositionallyIndexedElt()); *arrayNestedArray = false; if (haveObjField) { return dps::extractElementAtPathOrArrayAlongPath(obj, *field); } else if (positionalInfo.hasPositionallyIndexedElt()) { if (arrField.type() == Array) { *arrayNestedArray = true; } *field = positionalInfo.remainingPath; return positionalInfo.dottedElt; } return BSONElement(); }
void IndexSpec::_init(){ assert( keyPattern.objsize() ); string pluginName = IndexPlugin::findPluginName( keyPattern ); BSONObjBuilder nullKeyB; BSONObjIterator i( keyPattern ); while( i.more() ) { BSONElement e = i.next(); _fieldNames.push_back( e.fieldName() ); _fixed.push_back( BSONElement() ); nullKeyB.appendNull( "" ); } _nullKey = nullKeyB.obj(); BSONObjBuilder b; b.appendNull( "" ); _nullObj = b.obj(); _nullElt = _nullObj.firstElement(); if ( pluginName.size() ){ IndexPlugin * plugin = IndexPlugin::get( pluginName ); if ( ! plugin ){ log() << "warning: can't find plugin [" << pluginName << "]" << endl; } else { _indexType.reset( plugin->generate( this ) ); } } _finishedInit = true; }
SortStage::SortStage(const SortStageParams& params, WorkingSet* ws, PlanStage* child) : _ws(ws), _child(child), _pattern(params.pattern), _sorted(false), _resultIterator(_data.end()), _bounds(params.bounds), _hasBounds(params.hasBounds), _memUsage(0) { _cmp.reset(new WorkingSetComparator(_pattern)); // We'll need to treat arrays as if we were to create an index over them. that is, // we may need to unnest the first level and consider each array element to decide // the sort order. std::vector<const char *> fieldNames; std::vector<BSONElement> fixed; BSONObjIterator it(_pattern); while (it.more()) { BSONElement patternElt = it.next(); fieldNames.push_back(patternElt.fieldName()); fixed.push_back(BSONElement()); } _keyGen.reset(new BtreeKeyGeneratorV1(fieldNames, fixed, false /* not sparse */)); // See comment on the operator() call about sort semantics and why we need a // to use a bounds checker here. _boundsChecker.reset(new IndexBoundsChecker(&_bounds, _pattern, 1 /* == order */)); }
void getKeys( const BSONObj &obj, BSONObjSet &keys ) const { BSONElement loc = obj.getFieldDotted( _geo ); if ( loc.eoo() ) return; uassert( 13323 , "latlng not an array" , loc.isABSONObj() ); string root; { BSONObjIterator i( loc.Obj() ); BSONElement x = i.next(); BSONElement y = i.next(); root = makeString( hash(x) , hash(y) ); } verify( _other.size() == 1 ); BSONElementSet all; obj.getFieldsDotted( _other[0] , all ); if ( all.size() == 0 ) { _add( obj , root , BSONElement() , keys ); } else { for ( BSONElementSet::iterator i=all.begin(); i!=all.end(); ++i ) { _add( obj , root , *i , keys ); } } }
SortKeyGenerator::SortKeyGenerator(OperationContext* txn, const BSONObj& sortSpec, const BSONObj& queryObj) { _hasBounds = false; _sortHasMeta = false; _rawSortSpec = sortSpec; // 'sortSpec' can be a mix of $meta and index key expressions. We pick it apart so that // we only generate Btree keys for the index key expressions. // The Btree key fields go in here. We pass this fake index key pattern to the Btree // key generator below as part of generating sort keys for the docs. BSONObjBuilder btreeBob; BSONObjIterator it(sortSpec); while (it.more()) { BSONElement elt = it.next(); if (elt.isNumber()) { // Btree key. elt (should be) foo: 1 or foo: -1. btreeBob.append(elt); } else if (LiteParsedQuery::isTextScoreMeta(elt)) { _sortHasMeta = true; } else { // Sort spec. should have been validated before here. verify(false); } } // The fake index key pattern used to generate Btree keys. _btreeObj = btreeBob.obj(); // If we're just sorting by meta, don't bother with all the key stuff. if (_btreeObj.isEmpty()) { return; } // We'll need to treat arrays as if we were to create an index over them. that is, // we may need to unnest the first level and consider each array element to decide // the sort order. std::vector<const char*> fieldNames; std::vector<BSONElement> fixed; BSONObjIterator btreeIt(_btreeObj); while (btreeIt.more()) { BSONElement patternElt = btreeIt.next(); fieldNames.push_back(patternElt.fieldName()); fixed.push_back(BSONElement()); } // TODO SERVER-23095: change nullptr to the appropriate CollationInterface*. _keyGen.reset(new BtreeKeyGeneratorV1(fieldNames, fixed, false /* not sparse */, nullptr)); // The bounds checker only works on the Btree part of the sort key. getBoundsForSort(txn, queryObj, _btreeObj); if (_hasBounds) { _boundsChecker.reset(new IndexBoundsChecker(&_bounds, _btreeObj, 1 /* == order */)); } }
void IndexSpec::_init() { verify( keyPattern.objsize() ); // some basics _nFields = keyPattern.nFields(); _sparse = info["sparse"].trueValue(); uassert( 13529 , "sparse only works for single field keys" , ! _sparse || _nFields ); { // build _nullKey BSONObjBuilder b; BSONObjIterator i( keyPattern ); while( i.more() ) { BSONElement e = i.next(); _fieldNames.push_back( e.fieldName() ); _fixed.push_back( BSONElement() ); b.appendNull( "" ); } _nullKey = b.obj(); } { // _nullElt BSONObjBuilder b; b.appendNull( "" ); _nullObj = b.obj(); _nullElt = _nullObj.firstElement(); } { // _undefinedElt BSONObjBuilder b; b.appendUndefined( "" ); _undefinedObj = b.obj(); _undefinedElt = _undefinedObj.firstElement(); } { // handle plugins string pluginName = IndexPlugin::findPluginName( keyPattern ); if ( pluginName.size() ) { IndexPlugin * plugin = IndexPlugin::get( pluginName ); if ( ! plugin ) { log() << "warning: can't find plugin [" << pluginName << "]" << endl; } else { _indexType.reset( plugin->generate( this ) ); } } } _finishedInit = true; }
bool BSONElementIterator::subCursorHasMore() { // While we still are still finding arrays along the path, keep traversing deeper. while (_subCursor) { if (_subCursor->more()) { return true; } _subCursor.reset(); // If the subcursor doesn't have more, see if the current element is an array offset // match (see comment in BSONElementIterator::more() for an example). If it is indeed // an array offset match, create a new subcursor and examine it. if (_arrayIterationState.isArrayOffsetMatch(_arrayIterationState._current.fieldName())) { 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(_arrayIterationState._current, BSONElement()); _arrayIterationState._current = BSONElement(); return true; } _subCursorPath.reset(new ElementPath()); _subCursorPath->init(_arrayIterationState.restOfPath.substr( _arrayIterationState.nextPieceOfPath.size() + 1)); _subCursorPath->setLeafArrayBehavior(_path->leafArrayBehavior()); // If we're here, we must be able to traverse nonleaf arrays. dassert(_path->nonLeafArrayBehavior() == ElementPath::NonLeafArrayBehavior::kTraverse); dassert(_subCursorPath->nonLeafArrayBehavior() == ElementPath::NonLeafArrayBehavior::kTraverse); _subCursor.reset( new BSONElementIterator(_subCursorPath.get(), _arrayIterationState._current.Obj())); // 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(); } } return false; }
INT32 _ixmIndexKeyGen::getKeys ( const BSONObj &obj, BSONObjSet &keys, BSONElement *pArrEle ) const { ixmKeyGenerator g (this) ; if ( pArrEle ) { *pArrEle = BSONElement() ; } return g.getKeys ( obj, keys, pArrEle ) ; }
OpMsgRequest upconvertRequest(StringData db, BSONObj cmdObj, int queryFlags) { cmdObj = cmdObj.getOwned(); // Usually this is a no-op since it is already owned. auto readPrefContainer = BSONObj(); const StringData firstFieldName = cmdObj.firstElementFieldName(); if (firstFieldName == "$query" || firstFieldName == "query") { // Commands sent over OP_QUERY specify read preference by putting it at the top level and // putting the command in a nested field called either query or $query. // Check if legacyCommand has an invalid $maxTimeMS option. uassert(ErrorCodes::InvalidOptions, "cannot use $maxTimeMS query option with commands; use maxTimeMS command option " "instead", !cmdObj.hasField("$maxTimeMS")); if (auto readPref = cmdObj["$readPreference"]) readPrefContainer = readPref.wrap(); cmdObj = cmdObj.firstElement().Obj().shareOwnershipWith(cmdObj); } else if (auto queryOptions = cmdObj["$queryOptions"]) { // Mongos rewrites commands with $readPreference to put it in a field nested inside of // $queryOptions. Its command implementations often forward commands in that format to // shards. This function is responsible for rewriting it to a format that the shards // understand. readPrefContainer = queryOptions.Obj().shareOwnershipWith(cmdObj); cmdObj = cmdObj.removeField("$queryOptions"); } if (!readPrefContainer.isEmpty()) { cmdObj = BSONObjBuilder(std::move(cmdObj)).appendElements(readPrefContainer).obj(); } else if (!cmdObj.hasField("$readPreference") && (queryFlags & QueryOption_SlaveOk)) { BSONObjBuilder bodyBuilder(std::move(cmdObj)); ReadPreferenceSetting(ReadPreference::SecondaryPreferred).toContainingBSON(&bodyBuilder); cmdObj = bodyBuilder.obj(); } // Try to move supported array fields into document sequences. auto docSequenceIt = docSequenceFieldsForCommands.find(cmdObj.firstElementFieldName()); auto docSequenceElem = docSequenceIt == docSequenceFieldsForCommands.end() ? BSONElement() : cmdObj[docSequenceIt->second]; if (!isArrayOfObjects(docSequenceElem)) return OpMsgRequest::fromDBAndBody(db, std::move(cmdObj)); auto docSequenceName = docSequenceElem.fieldNameStringData(); // Note: removing field before adding "$db" to avoid the need to copy the potentially large // array. auto out = OpMsgRequest::fromDBAndBody(db, cmdObj.removeField(docSequenceName)); out.sequences.push_back({docSequenceName.toString()}); for (auto elem : docSequenceElem.Obj()) { out.sequences[0].objs.push_back(elem.Obj().shareOwnershipWith(cmdObj)); } return out; }
int ixmBucketManager::ixmBucket::removeIndex(unsigned int hashNum, ixmEleHash &eleHash) { int rc = EDB_OK; BSONElement destEle; BSONElement sourEle; ixmEleHash existEle; std::pair<std::multimap<unsigned int, ixmEleHash>::iterator, std::multimap<unsigned int, ixmEleHash>::iterator> ret; _mutex.get(); ret = _bucketMap.equal_range(hashNum); sourEle = BSONElement(eleHash.data); for(std::multimap<unsigned int, ixmEleHash>::iterator it = ret.first; it != ret.second; ++it) { existEle = it->second; destEle = BSONElement(existEle.data); if(sourEle.type() == destEle.type()) { if(sourEle.valuesize() == destEle.valuesize()) { if(!memcmp(sourEle.value(), destEle.value(), destEle.valuesize())) { eleHash.recordID = existEle.recordID; _bucketMap.erase(it); goto done; } } } } rc = EDB_INVALIDARG; PD_LOG(PDERROR, "record _id does not exist"); goto error; done: _mutex.release(); return rc; error: goto done; }
BSONElement extractElementAtPathOrArrayAlongPath(const BSONObj& obj, const char*& path) { const char* p = strchr(path, '.'); BSONElement sub; if (p) { sub = obj.getField(std::string(path, p - path)); path = p + 1; } else { sub = obj.getField(path); path = path + strlen(path); } if (sub.eoo()) return BSONElement(); else if (sub.type() == Array || path[0] == '\0') return sub; else if (sub.type() == Object) return extractElementAtPathOrArrayAlongPath(sub.embeddedObject(), path); else return BSONElement(); }
void BSONElementIterator::reset(const ElementPath* path, size_t suffixIndex, BSONElement elementToIterate) { _path = path; _traversalStartIndex = 0; _traversalStart = BSONElement(); _setTraversalStart(suffixIndex, elementToIterate); _state = BEGIN; _next.reset(); _subCursor.reset(); _subCursorPath.reset(); }
BSONElement BSONObj::getFieldUsingIndexNames(const char *fieldName, const BSONObj &indexKey) const { BSONObjIterator i( indexKey ); int j = 0; while( i.more() ) { BSONElement f = i.next(); if ( f.eoo() ) return BSONElement(); if ( strcmp( f.fieldName(), fieldName ) == 0 ) break; ++j; } BSONObjIterator k( *this ); while( k.more() ) { BSONElement g = k.next(); if ( g.eoo() ) return BSONElement(); if ( j == 0 ) { return g; } --j; } return BSONElement(); }
BSONElement extractElementAtPath(const BSONObj& obj, StringData path) { BSONElement e = obj.getField(path); if (e.eoo()) { size_t dot_offset = path.find('.'); if (dot_offset != std::string::npos) { StringData left = path.substr(0, dot_offset); StringData right = path.substr(dot_offset + 1); BSONObj sub = obj.getObjectField(left); return sub.isEmpty() ? BSONElement() : extractElementAtPath(sub, right); } } return e; }
int ixmBucketManager::ixmBucket::isIDExist(unsigned int hashNum, ixmEleHash &eleHash) { int rc = EDB_OK; BSONElement destEle; BSONElement sourEle; ixmEleHash existEle; std::pair<std::multimap<unsigned int, ixmEleHash>::iterator, std::multimap<unsigned int, ixmEleHash>::iterator> ret; _mutex.get_shared(); ret = _bucketMap.equal_range(hashNum); sourEle = BSONElement(eleHash.data); for(std::multimap<unsigned int, ixmEleHash>::iterator it = ret.first; it != ret.second; ++it) { existEle = it->second; destEle = BSONElement(existEle.data); if(sourEle.type() == destEle.type()) { if(sourEle.valuesize() == destEle.valuesize()) { if(!memcmp(sourEle.value(), destEle.value(), destEle.valuesize())) { rc = EDB_IXM_ID_EXIST; PD_LOG(PDERROR, "record _id does exist"); goto error; } } } } done: _mutex.release_shared(); return rc; error: goto done; }
bool BSONElementIterator::subCursorHasMore() { // While we still are still finding arrays along the path, keep traversing deeper. while (_subCursor) { if (_subCursor->more()) { return true; } _subCursor.reset(); // If the subcursor doesn't have more, see if the current element is an array offset // match (see comment in BSONElementIterator::more() for an example). If it is indeed // an array offset match, create a new subcursor and examine it. if (_arrayIterationState.isArrayOffsetMatch(_arrayIterationState._current.fieldName())) { if (_arrayIterationState.nextEntireRest()) { // Our path terminates at the array offset. _next should point at the current // array element. _next.reset(_arrayIterationState._current, _arrayIterationState._current, true); _arrayIterationState._current = BSONElement(); return true; } _subCursorPath.reset(new ElementPath()); _subCursorPath->init(_arrayIterationState.restOfPath.substr( _arrayIterationState.nextPieceOfPath.size() + 1)); _subCursorPath->setTraverseLeafArray(_path->shouldTraverseLeafArray()); // If we're here, we must be able to traverse nonleaf arrays. dassert(_path->shouldTraverseNonleafArrays()); dassert(_subCursorPath->shouldTraverseNonleafArrays()); _subCursor.reset( new BSONElementIterator(_subCursorPath.get(), _arrayIterationState._current.Obj())); _arrayIterationState._current = BSONElement(); } } return false; }
///PD_TRACE_DECLARE_FUNCTION ( SDB__MTHELEMMATCHGETN, "mthElemMatchGetN" ) static INT32 mthElemMatchGetN( const CHAR *fieldName, const bson::BSONElement &in, _mthSAction *action, bson::BSONElement &out, INT32 n ) { INT32 rc = SDB_OK ; PD_TRACE_ENTRY( SDB__MTHELEMMATCHGETN ) ; if ( Array == in.type() ) { BSONObjBuilder objBuilder ; BSONArrayBuilder arrayBuilder( objBuilder.subarrayStart( fieldName ) ) ; _mthElemMatchIterator i( in.embeddedObject(), &( action->getMatcher() ), n ) ; do { BSONElement next ; rc = i.next( next ) ; if ( SDB_OK == rc ) { arrayBuilder.append( next ) ; } else if ( SDB_DMS_EOC == rc ) { arrayBuilder.doneFast() ; rc = SDB_OK ; break ; } else { PD_LOG( PDERROR, "failed to get next element:%d", rc ) ; goto error ; } } while ( TRUE ) ; action->setObj( objBuilder.obj() ) ; out = action->getObj().getField( fieldName ) ; } else { out = BSONElement() ; } done: PD_TRACE_EXITRC( SDB__MTHELEMMATCHGETN, rc ) ; return rc ; error: goto done ; }
BSONElement getErrField(const BSONObj& o) { BSONElement first = o.firstElement(); if( strcmp(first.fieldName(), "$err") == 0 ) return first; // temp - will be DEV only later /*DEV*/ if( 1 ) { BSONElement e = o["$err"]; if( !e.eoo() ) { wassert(false); } return e; } return BSONElement(); }
// PD_TRACE_DECLARE_FUNCTION ( SDB__IXMINXKEYGEN__INIT, "_ixmIndexKeyGen::_init" ) void _ixmIndexKeyGen::_init() { PD_TRACE_ENTRY ( SDB__IXMINXKEYGEN__INIT ); _nFields = _keyPattern.nFields () ; INT32 fieldNum = 0 ; { BSONObjIterator i(_keyPattern) ; while ( i.more()) { BSONElement e = i.next() ; _fieldNames.push_back(e.fieldName()) ; _fixedElements.push_back(BSONElement()) ; ++fieldNum ; } _undefinedKey = ixmGetUndefineKeyObj( fieldNum ) ; } PD_TRACE_EXIT ( SDB__IXMINXKEYGEN__INIT ); }
BSONElement getFieldDottedOrArray( const BSONObj& doc, const FieldRef& path, size_t* idxPath ) { if ( path.numParts() == 0 ) return doc.getField( "" ); BSONElement res; BSONObj curr = doc; bool stop = false; size_t partNum = 0; while ( partNum < path.numParts() && !stop ) { res = curr.getField( path.getPart( partNum ) ); switch ( res.type() ) { case EOO: stop = true; break; case Object: curr = res.Obj(); ++partNum; break; case Array: stop = true; break; default: if ( partNum+1 < path.numParts() ) { res = BSONElement(); } stop = true; } } *idxPath = partNum; return res; }
void getKeys(const BSONObj &obj, BSONObjSet &keys) const { BSONElement loc = obj.getFieldDotted(_geoField); if (loc.eoo()) return; uassert(13323, "latlng not an array", loc.isABSONObj()); string root; { BSONObjIterator i(loc.Obj()); BSONElement x = i.next(); BSONElement y = i.next(); root = makeString(hash(x), hash(y)); } verify(_otherFields.size() == 1); BSONElementSet all; // This is getFieldsDotted (plural not singular) since the object we're indexing // may be an array. obj.getFieldsDotted(_otherFields[0], all); if (all.size() == 0) { // We're indexing a document that doesn't have the secondary non-geo field present. // XXX: do we want to add this even if all.size() > 0? result:empty search terms // match everything instead of only things w/empty search terms) addKey(root, BSONElement(), keys); } else { // Ex:If our secondary field is type: "foo" or type: {a:"foo", b:"bar"}, // all.size()==1. We can query on the complete field. // Ex: If our secondary field is type: ["A", "B"] all.size()==2 and all has values // "A" and "B". The query looks for any of the fields in the array. for (BSONElementSet::iterator i = all.begin(); i != all.end(); ++i) { addKey(root, *i, keys); } } }
// Standard Btree implementation below. BtreeAccessMethod::BtreeAccessMethod(IndexCatalogEntry* btreeState) : BtreeBasedAccessMethod(btreeState) { // The key generation wants these values. vector<const char*> fieldNames; vector<BSONElement> fixed; BSONObjIterator it(_descriptor->keyPattern()); while (it.more()) { BSONElement elt = it.next(); fieldNames.push_back(elt.fieldName()); fixed.push_back(BSONElement()); } if (0 == _descriptor->version()) { _keyGenerator.reset(new BtreeKeyGeneratorV0(fieldNames, fixed, _descriptor->isSparse())); } else if (1 == _descriptor->version()) { _keyGenerator.reset(new BtreeKeyGeneratorV1(fieldNames, fixed, _descriptor->isSparse())); } else { massert(16745, "Invalid index version for key generation.", false ); } }
void ElementIterator::Context::reset() { _element = BSONElement(); }
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 ( _subCursor ) { if ( _subCursor->more() ) return true; _subCursor.reset(); if ( _arrayIterationState.isArrayOffsetMatch( _arrayIterationState._current.fieldName() ) ) { if ( _arrayIterationState.nextEntireRest() ) { _next.reset( _arrayIterationState._current, _arrayIterationState._current, true ); _arrayIterationState._current = BSONElement(); return true; } _subCursorPath.reset( new ElementPath() ); _subCursorPath->init( _arrayIterationState.restOfPath.substr( _arrayIterationState.nextPieceOfPath.size() + 1 ) ); _subCursorPath->setTraverseLeafArray( _path->shouldTraverseLeafArray() ); _subCursor.reset( new BSONElementIterator( _subCursorPath.get(), _arrayIterationState._current.Obj() ) ); _arrayIterationState._current = BSONElement(); return more(); } } 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; } // its an array _arrayIterationState.reset( _path->fieldRef(), idxPath + 1 ); if ( !_arrayIterationState.hasMore && !_path->shouldTraverseLeafArray() ) { _next.reset( e, BSONElement(), true ); _state = DONE; return true; } _arrayIterationState.startIterator( e ); _state = IN_ARRAY; return more(); } if ( _state == IN_ARRAY ) { while ( _arrayIterationState.more() ) { BSONElement x = _arrayIterationState.next(); if ( !_arrayIterationState.hasMore ) { _next.reset( x, x, false ); return true; } // i have deeper to go if ( x.type() == Object ) { _subCursorPath.reset( new ElementPath() ); _subCursorPath->init( _arrayIterationState.restOfPath ); _subCursorPath->setTraverseLeafArray( _path->shouldTraverseLeafArray() ); _subCursor.reset( new BSONElementIterator( _subCursorPath.get(), x.Obj() ) ); return more(); } if ( _arrayIterationState.isArrayOffsetMatch( x.fieldName() ) ) { if ( _arrayIterationState.nextEntireRest() ) { _next.reset( x, x, false ); return true; } if ( x.isABSONObj() ) { _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( x ); real->_state = IN_ARRAY; _arrayIterationState._current = BSONElement(); return more(); } } } if ( _arrayIterationState.hasMore ) return false; _next.reset( _arrayIterationState._theArray, BSONElement(), true ); _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; }