void run() { // Insert a ton of documents with a: 1 for (size_t i = 0; i < 1000; ++i) { insert(BSON("a" << 1)); } // Insert a ton of other documents with a: 2 for (size_t i = 0; i < 1000; ++i) { insert(BSON("a" << 2)); } // Make an index on a:1 addIndex(BSON("a" << 1)); AutoGetCollectionForRead ctx(&_txn, ns()); Collection* coll = ctx.getCollection(); // Set up the distinct stage. std::vector<IndexDescriptor*> indexes; coll->getIndexCatalog()->findIndexesByKeyPattern(&_txn, BSON("a" << 1), false, &indexes); ASSERT_EQ(indexes.size(), 1U); DistinctParams params; params.descriptor = indexes[0]; params.direction = 1; // Distinct-ing over the 0-th field of the keypattern. params.fieldNo = 0; // We'll look at all values in the bounds. params.bounds.isSimpleRange = false; OrderedIntervalList oil("a"); oil.intervals.push_back(IndexBoundsBuilder::allValues()); params.bounds.fields.push_back(oil); WorkingSet ws; DistinctScan distinct(&_txn, params, &ws); WorkingSetID wsid; // Get our first result. int firstResultWorks = 0; while (PlanStage::ADVANCED != distinct.work(&wsid)) { ++firstResultWorks; } // 5 is a bogus number. There's some amount of setup done by the first few calls but // we should return the first result relatively promptly. ASSERT_LESS_THAN(firstResultWorks, 5); ASSERT_EQUALS(1, getIntFieldDotted(ws, wsid, "a")); // Getting our second result should be very quick as we just skip // over the first result. int secondResultWorks = 0; while (PlanStage::ADVANCED != distinct.work(&wsid)) { ++secondResultWorks; } ASSERT_EQUALS(2, getIntFieldDotted(ws, wsid, "a")); // This is 0 because we don't have to loop for several values; we just skip over // all the 'a' values. ASSERT_EQUALS(0, secondResultWorks); ASSERT_EQUALS(PlanStage::IS_EOF, distinct.work(&wsid)); }
void run() { // Insert a ton of documents with a: [1, 2, 3] for (size_t i = 0; i < 1000; ++i) { insert(BSON("a" << BSON_ARRAY(1 << 2 << 3))); } // Insert a ton of other documents with a: [4, 5, 6] for (size_t i = 0; i < 1000; ++i) { insert(BSON("a" << BSON_ARRAY(4 << 5 << 6))); } // Make an index on a:1 addIndex(BSON("a" << 1)); AutoGetCollectionForRead ctx(&_txn, ns()); Collection* coll = ctx.getCollection(); // Set up the distinct stage. std::vector<IndexDescriptor*> indexes; coll->getIndexCatalog()->findIndexesByKeyPattern(&_txn, BSON("a" << 1), false, &indexes); verify(indexes.size() == 1); DistinctParams params; params.descriptor = indexes[0]; ASSERT_TRUE(params.descriptor->isMultikey(&_txn)); verify(params.descriptor); params.direction = 1; // Distinct-ing over the 0-th field of the keypattern. params.fieldNo = 0; // We'll look at all values in the bounds. params.bounds.isSimpleRange = false; OrderedIntervalList oil("a"); oil.intervals.push_back(IndexBoundsBuilder::allValues()); params.bounds.fields.push_back(oil); WorkingSet ws; DistinctScan distinct(&_txn, params, &ws); // We should see each number in the range [1, 6] exactly once. std::set<int> seen; WorkingSetID wsid; PlanStage::StageState state; while (PlanStage::IS_EOF != (state = distinct.work(&wsid))) { if (PlanStage::ADVANCED == state) { // Check int value. int currentNumber = getIntFieldDotted(ws, wsid, "a"); ASSERT_GREATER_THAN_OR_EQUALS(currentNumber, 1); ASSERT_LESS_THAN_OR_EQUALS(currentNumber, 6); // Should see this number only once. ASSERT_TRUE(seen.find(currentNumber) == seen.end()); seen.insert(currentNumber); } } ASSERT_EQUALS(6U, seen.size()); }
// static OrderedIntervalList IndexBoundsBuilder::allValuesForField(const BSONElement& elt) { // ARGH, BSONValue would make this shorter. BSONObjBuilder bob; if (-1 == elt.number()) { // Index should go from MaxKey to MinKey as it's descending. bob.appendMaxKey(""); bob.appendMinKey(""); } else { // Index goes from MinKey to MaxKey as it's ascending. bob.appendMinKey(""); bob.appendMaxKey(""); } OrderedIntervalList oil(elt.fieldName()); oil.intervals.push_back(makeRangeInterval(bob.obj(), true, true)); return oil; }
IndexScan* createIndexScan(BSONObj startKey, BSONObj endKey, bool startInclusive, bool endInclusive, int direction = 1) { IndexCatalog* catalog = _coll->getIndexCatalog(); std::vector<IndexDescriptor*> indexes; catalog->findIndexesByKeyPattern(&_opCtx, BSON("x" << 1), false, &indexes); ASSERT_EQ(indexes.size(), 1U); IndexScanParams params(&_opCtx, *indexes[0]); params.direction = direction; OrderedIntervalList oil("x"); BSONObjBuilder bob; bob.appendAs(startKey.firstElement(), ""); bob.appendAs(endKey.firstElement(), ""); oil.intervals.push_back(Interval(bob.obj(), startInclusive, endInclusive)); params.bounds.fields.push_back(oil); MatchExpression* filter = NULL; return new IndexScan(&_opCtx, params, &_ws, filter); }
IndexScan* createIndexScan(BSONObj startKey, BSONObj endKey, bool startInclusive, bool endInclusive, int direction = 1) { IndexCatalog* catalog = _coll->getIndexCatalog(); IndexDescriptor* descriptor = catalog->findIndexByKeyPattern(&_txn, BSON("x" << 1)); invariant(descriptor); IndexScanParams params; params.descriptor = descriptor; params.direction = direction; OrderedIntervalList oil("x"); BSONObjBuilder bob; bob.appendAs(startKey.firstElement(), ""); bob.appendAs(endKey.firstElement(), ""); oil.intervals.push_back(Interval(bob.obj(), startInclusive, endInclusive)); params.bounds.fields.push_back(oil); MatchExpression* filter = NULL; return new IndexScan(&_txn, params, &_ws, filter); }