void Projection::validateQuery( const BSONObj query ) const { // this function only validates positional operator ($) projections if ( getArrayOpType() != ARRAY_OP_POSITIONAL && getArrayOpType() != ARRAY_OP_POSITIONAL_KEYED ) return; BSONObjIterator querySpecIter( query ); while ( querySpecIter.more() ) { // for each query element BSONElement queryElement = querySpecIter.next(); if ( mongoutils::str::equals( queryElement.fieldName(), "$and" ) ) // don't check $and to avoid deep comparison of the arguments. // TODO: can be replaced with Matcher::FieldSink when complete (SERVER-4644) return; BSONObjIterator projectionSpecIter( getSpec() ); while ( projectionSpecIter.more() ) { // for each projection element BSONElement projectionElement = projectionSpecIter.next(); if ( mongoutils::str::contains( projectionElement.fieldName(), ".$" ) && mongoutils::str::before( queryElement.fieldName(), '.' ) == mongoutils::str::before( projectionElement.fieldName(), "." ) ) { // found query spec that matches positional array projection spec LOG(4) << "Query specifies field named for positional operator: " << queryElement.fieldName() << endl; return; } } } uasserted( 16354, "Positional operator does not match the query specifier." ); }
void Projection::transform( const BSONObj& in , BSONObjBuilder& b, const MatchDetails* details ) const { const ArrayOpType& arrayOpType = getArrayOpType(); BSONObjIterator i(in); while ( i.more() ) { BSONElement e = i.next(); if ( mongoutils::str::equals( "_id" , e.fieldName() ) ) { if ( _includeID ) b.append( e ); } else { Matchers::const_iterator matcher = _matchers.find( e.fieldName() ); if ( matcher == _matchers.end() ) { // no array projection matchers for this field append( b, e, details, arrayOpType ); } else { // field has array projection with $elemMatch specified. massert( 16348, "matchers are only supported for $elemMatch", arrayOpType == ARRAY_OP_ELEM_MATCH ); MatchDetails arrayDetails; arrayDetails.requestElemMatchKey(); if ( matcher->second->matches( in, &arrayDetails ) ) { LOG(4) << "Matched array on field: " << matcher->first << endl << " from array: " << in.getField( matcher->first ) << endl << " in object: " << in << endl << " at position: " << arrayDetails.elemMatchKey() << endl; FieldMap::const_iterator field = _fields.find( e.fieldName() ); massert( 16349, "$elemMatch specified, but projection field not found.", field != _fields.end() ); BSONArrayBuilder a; BSONObjBuilder o; massert( 16350, "$elemMatch called on document element with eoo", ! in.getField( e.fieldName() ).eoo() ); massert( 16351, "$elemMatch called on array element with eoo", ! in.getField( e.fieldName() ).Obj().getField( arrayDetails.elemMatchKey() ).eoo() ); a.append( in.getField( e.fieldName() ).Obj() .getField( arrayDetails.elemMatchKey() ) ); o.appendArray( matcher->first, a.arr() ); append( b, o.done().firstElement(), details, arrayOpType ); } } } } }