
# 避免hideIndex导致游标失效
#### 失效场景
在 DDS 中，某些索引操作可能导致游标失效，DDS这些行为和社区版MongoDB行为一致。以下是几个常见的例子及其解释：
#### hideIndex导致游标失效
**原因：**
hideIndex操作改变了索引的元数据，从而使现有游标失效。
**示例代码：**
```
(function() {
"use strict";
let collName = "test_coll";
let coll = db.getCollection(collName);
coll.drop();
// 创建索引，并插入数据，
coll.createIndex({x: 1}, {background: false});
for (var i = 0; i < 1000; ++i) {
coll.insert({x: i});
}
// 获取游标
let cursor = coll.find({x: {$gte: 1}});
// 使用游标，但是游标并没有使用完
for (var i = 0; i < 101; ++i) {
let doc = cursor.next();
print(tojson(doc));
}
// 在游标使用完之前隐藏索引
coll.hideIndex("x_1");
// 遍历游标
cursor.forEach((doc) => {
// 游标会报错：
// "errmsg" : "definition of index 'x_1' changed"
// "codeName" : "QueryPlanKilled"
print(tojson(doc));
});
})();
```
**结果：**
游标失效，可能抛出错误。
```
2024-12-24T16:26:42.445+0800 E QUERY    [js] Error: getMore command failed: {
"ok" : 0,
"errmsg" : "definition of index 'x_1' changed",
"code" : 175,
"codeName" : "QueryPlanKilled"
} :
```
#### dropIndex 导致游标失效
**原因：**
删除索引后，DDS需要重新计算查询计划，从而使现有游标失效。
**示例代码：**
```
(function() {
"use strict";
let collName = "test_coll";
let coll = db.getCollection(collName);
coll.drop();
// 创建索引，并插入数据，
coll.createIndex({x: 1}, {background: false});
for (var i = 0; i < 1000; ++i) {
coll.insert({x: i});
}
// 获取游标
let cursor = coll.find({x: {$gte: 1}});
// 使用游标，但是游标并没有使用完
for (var i = 0; i < 101; ++i) {
let doc = cursor.next();
print(tojson(doc));
}
// 在游标使用完之前删除索引
coll.dropIndex("x_1");
// 遍历游标
cursor.forEach((doc) => {
// 游标会报错：
// "errmsg" : "index 'x_1' dropped",
// "codeName" : "QueryPlanKilled"
print(tojson(doc));
});
})();
```
**结果：**
游标失效，因为删除索引会导致查询计划需要重新计算。
```
2024-12-25T10:34:29.948+0800 E QUERY    [js] Error: getMore command failed: {
"ok" : 0,
"errmsg" : "index 'x_1' dropped",
"code" : 175,
"codeName" : "QueryPlanKilled"
}
```
#### renameCollection导致游标失效
**原因：**
修改集合结构renameCollection也会导致游标失效。
**示例代码：**
```
(function() {
"use strict";
let collName = "test_coll";
let coll = db.getCollection(collName);
coll.drop();
// 创建索引，并插入数据，
coll.createIndex({x: 1}, {background: false});
for (var i = 0; i < 1000; ++i) {
coll.insert({x: i});
}
// 获取游标
let cursor = coll.find({x: {$gte: 1}});
// 使用游标，但是游标并没有使用完
for (var i = 0; i < 101; ++i) {
let doc = cursor.next();
print(tojson(doc));
}
// 在游标使用完之前重命名集合
coll.renameCollection("test_coll_reaname");
// 遍历游标
cursor.forEach((doc) => {
// 游标会报错：
// "errmsg" : "collection dropped between getMore calls",
// "codeName" : "OperationFailed"
print(tojson(doc));
});
})();
```
**结果：**
游标失效，因为集合的名称改变，游标失去了上下文。
```
2024-12-25T10:39:28.624+0800 E QUERY    [js] Error: getMore command failed: {
"ok" : 0,
"errmsg" : "collection dropped between getMore calls",
"code" : 96,
"codeName" : "OperationFailed"
} :
```
#### dropCollection导致游标失效
**原因：**
删除集合游标失去了上下文，会导致游标失效。
**示例代码：**
```
(function() {
"use strict";
let collName = "test_coll";
let coll = db.getCollection(collName);
coll.drop();
// 创建索引，并插入数据，
coll.createIndex({x: 1}, {background: false});
for (var i = 0; i < 1000; ++i) {
coll.insert({x: i});
}
// 获取游标
let cursor = coll.find({x: {$gte: 1}});
// 使用游标，但是游标并没有使用完
for (var i = 0; i < 101; ++i) {
let doc = cursor.next();
print(tojson(doc));
}
// 在游标使用完之前删除集合
coll.drop();
// 遍历游标
cursor.forEach((doc) => {
// 游标会报错：
// "errmsg" : "collection dropped between getMore calls",
// "codeName" : "OperationFailed"
print(tojson(doc));
});
})();
```
**结果：**
游标失效，因为集合已经被删除，游标失去了上下文。
```
2024-12-25T10:40:33.737+0800 E QUERY    [js] Error: getMore command failed: {
"ok" : 0,
"errmsg" : "collection dropped between getMore calls",
"code" : 96,
"codeName" : "OperationFailed"
} :
```
#### 解决方法
- 在索引操作之前处理游标： 确保在 hideIndex 或 dropIndex 之前使用完游标。
- 重新获取游标： 如果索引发生变化，重新执行查询以获取新的游标。
- 提前计划： 避免在长时间查询中执行索引操作。
**示例代码：**
```
(function() {
"use strict";
let collName = "test_coll";
let coll = db.getCollection(collName);
coll.drop();
// 创建索引，并插入数据，
coll.createIndex({x: 1}, {background: false});
for (var i = 0; i < 1000; ++i) {
coll.insert({x: i});
}
// 获取游标
let cursor = coll.find({x: {$gte: 1}});
// 使用游标，但是游标并没有使用完
for (var i = 0; i < 101; ++i) {
let doc = cursor.next();
print(tojson(doc));
}
// 在游标使用完之前隐藏索引
coll.hideIndex("x_1");
// 遍历游标
// cursor.forEach((doc) => {
// 游标会报错：
// "errmsg" : "definition of index 'x_1' changed"
// "codeName" : "QueryPlanKilled"
// print(tojson(doc));
// });
// 重新获取游标
cursor = coll.find({x: {$gte: 1}});
cursor.forEach((doc) => {
print(tojson(doc));
});
})();
```
