Example #1
0
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 */));
    }
}
Example #2
0
Status SortKeyGenerator::getSortKey(const WorkingSetMember& member, BSONObj* objOut) const {
    BSONObj btreeKeyToUse;

    Status btreeStatus = getBtreeKey(member.obj.value(), &btreeKeyToUse);
    if (!btreeStatus.isOK()) {
        return btreeStatus;
    }

    if (!_sortHasMeta) {
        *objOut = btreeKeyToUse;
        return Status::OK();
    }

    BSONObjBuilder mergedKeyBob;

    // Merge metadata into the key.
    BSONObjIterator it(_rawSortSpec);
    BSONObjIterator btreeIt(btreeKeyToUse);
    while (it.more()) {
        BSONElement elt = it.next();
        if (elt.isNumber()) {
            // Merge btree key elt.
            mergedKeyBob.append(btreeIt.next());
        } else if (LiteParsedQuery::isTextScoreMeta(elt)) {
            // Add text score metadata
            double score = 0.0;
            if (member.hasComputed(WSM_COMPUTED_TEXT_SCORE)) {
                const TextScoreComputedData* scoreData = static_cast<const TextScoreComputedData*>(
                    member.getComputed(WSM_COMPUTED_TEXT_SCORE));
                score = scoreData->getScore();
            }
            mergedKeyBob.append("$metaTextScore", score);
        }
    }

    *objOut = mergedKeyBob.obj();
    return Status::OK();
}