Пример #1
0
    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." );
    }
Пример #2
0
    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 );
                    }
                }
            }
        }
    }