如何同时用范围约束一个键和用精确匹配约束另一个键?
How to simultaneously constrain one key with a range and constrain another key with an exact match?
我创建了一个测试 Node.js 脚本,该脚本使用 Nano 生成一些示例数据文档、创建两个视图和 运行 两个测试查询。每个数据文档都有两个键:"a" 和 "b"。我希望我的查询结果是 "a" 介于 1 和 3 之间且 "b" 等于 2 的所有文档。我测试了我在网上找到的 view/query 模式,它使用一个 startkey
数组和一个 endkey
数组。但是,当我在约束 "b" 之前约束 "a" 时,它的行为并不像预期的那样,但是当我在约束 "a" 之前约束 "b" 时,它确实表现得像预期的那样。
为什么 b_then_a
视图似乎有效但 a_then_b
视图无效?这种方法不正确吗?脚本及其输出如下。
var nano = require("nano")("http://HCOADAMM:HcoAdammRSM@localhost:5984");
let jasonDB = nano.db.use("jason");
const DESIGN_DOCUMENT_NAME = "findtest";
var testData = [
{ a: 1, b: 1 },
{ a: 1, b: 2 },
{ a: 1, b: 3 },
{ a: 1, b: 4 },
{ a: 2, b: 1 },
{ a: 2, b: 2 },
{ a: 2, b: 3 },
{ a: 2, b: 4 },
{ a: 3, b: 1 },
{ a: 3, b: 2 },
{ a: 3, b: 3 },
{ a: 3, b: 4 },
{ a: 4, b: 1 },
{ a: 4, b: 2 },
{ a: 4, b: 3 },
{ a: 4, b: 4 }
];
var shuffleArray = function(arrayIn) {
var arrayInLength = arrayIn.length;
var arrayOut = [];
while(arrayInLength)
arrayOut.push(arrayIn.splice(
parseInt(Math.random() * (arrayInLength--)), 1
)[0]);
return arrayOut;
}
var createTestRecords = function() {
var recordsShuffled = shuffleArray(testData);
recordsShuffled.forEach(function(record) {
jasonDB.insert(
record,
function(err, body) {
if(err)
console.log(err);
else
console.log("updated user doc " + JSON.stringify(body));
}
);
});
}
var createDesignDocument = function() {
jasonDB.get("_design/" + DESIGN_DOCUMENT_NAME, {}, function(err, body, headers) {
if(!err || err.error === "not_found") {
var dbObject = new Object();
dbObject._id = "_design/" + DESIGN_DOCUMENT_NAME;
if(!err) {
dbObject._rev = body._rev;
}
dbObject.language = "javascript";
dbObject.views = {
a_then_b: {
map: function(doc) {
emit([doc.a, doc.b]);
}
},
b_then_a: {
map: function(doc) {
emit([doc.b, doc.a]);
}
},
};
jasonDB.insert(dbObject, function(err, body, header) {
if(err) {
console.log("insert error:");
console.log(err);
} else {
console.log("created " + "jason/_design/" + DESIGN_DOCUMENT_NAME);
}
})
} else {
console.log("get error:");
console.log(err);
}
});
}
var queryTest = function() {
jasonDB.view(
DESIGN_DOCUMENT_NAME,
"a_then_b",
{ startkey: [1, 2], endkey: [3, 2] },
function(err, body) {
if(err) {
console.log(err);
} else {
console.log("a_then_b")
body.rows.forEach(function(el) {
console.log(el);
});
console.log("body.rows.length = " + body.rows.length);
console.log("");
}
}
);
jasonDB.view(
DESIGN_DOCUMENT_NAME,
"b_then_a",
{ startkey: [2, 1], endkey: [2, 3] },
function(err, body) {
if(err) {
console.log(err);
} else {
console.log("b_then_a")
body.rows.forEach(function(el) {
console.log(el);
});
console.log("body.rows.length = " + body.rows.length);
}
}
);
}
//createTestRecords();
//createDesignDocument();
setTimeout(function() {
queryTest();
}, 1000);
输出:
a_then_b
{ id: '812f16b3826569ec94eb35d087030d64',
key: [ 1, 2 ],
value: null }
{ id: '812f16b3826569ec94eb35d087030709',
key: [ 1, 3 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702a846',
key: [ 1, 4 ],
value: null }
{ id: '812f16b3826569ec94eb35d087032077',
key: [ 2, 1 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702fd89',
key: [ 2, 2 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702caee',
key: [ 2, 3 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702c32a',
key: [ 2, 4 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702b358',
key: [ 3, 1 ],
value: null }
{ id: '812f16b3826569ec94eb35d087031386',
key: [ 3, 2 ],
value: null }
body.rows.length = 9
b_then_a
{ id: '812f16b3826569ec94eb35d087030d64',
key: [ 2, 1 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702fd89',
key: [ 2, 2 ],
value: null }
{ id: '812f16b3826569ec94eb35d087031386',
key: [ 2, 3 ],
value: null }
body.rows.length = 3
如果第二个键是索引中的第一个键,您只能这样做。所以你需要尊重索引中的键,这样 b
首先被索引, a
第二。这将允许您在 [2,1]
到 [2,3]
的范围内搜索。
我创建了一个测试 Node.js 脚本,该脚本使用 Nano 生成一些示例数据文档、创建两个视图和 运行 两个测试查询。每个数据文档都有两个键:"a" 和 "b"。我希望我的查询结果是 "a" 介于 1 和 3 之间且 "b" 等于 2 的所有文档。我测试了我在网上找到的 view/query 模式,它使用一个 startkey
数组和一个 endkey
数组。但是,当我在约束 "b" 之前约束 "a" 时,它的行为并不像预期的那样,但是当我在约束 "a" 之前约束 "b" 时,它确实表现得像预期的那样。
为什么 b_then_a
视图似乎有效但 a_then_b
视图无效?这种方法不正确吗?脚本及其输出如下。
var nano = require("nano")("http://HCOADAMM:HcoAdammRSM@localhost:5984");
let jasonDB = nano.db.use("jason");
const DESIGN_DOCUMENT_NAME = "findtest";
var testData = [
{ a: 1, b: 1 },
{ a: 1, b: 2 },
{ a: 1, b: 3 },
{ a: 1, b: 4 },
{ a: 2, b: 1 },
{ a: 2, b: 2 },
{ a: 2, b: 3 },
{ a: 2, b: 4 },
{ a: 3, b: 1 },
{ a: 3, b: 2 },
{ a: 3, b: 3 },
{ a: 3, b: 4 },
{ a: 4, b: 1 },
{ a: 4, b: 2 },
{ a: 4, b: 3 },
{ a: 4, b: 4 }
];
var shuffleArray = function(arrayIn) {
var arrayInLength = arrayIn.length;
var arrayOut = [];
while(arrayInLength)
arrayOut.push(arrayIn.splice(
parseInt(Math.random() * (arrayInLength--)), 1
)[0]);
return arrayOut;
}
var createTestRecords = function() {
var recordsShuffled = shuffleArray(testData);
recordsShuffled.forEach(function(record) {
jasonDB.insert(
record,
function(err, body) {
if(err)
console.log(err);
else
console.log("updated user doc " + JSON.stringify(body));
}
);
});
}
var createDesignDocument = function() {
jasonDB.get("_design/" + DESIGN_DOCUMENT_NAME, {}, function(err, body, headers) {
if(!err || err.error === "not_found") {
var dbObject = new Object();
dbObject._id = "_design/" + DESIGN_DOCUMENT_NAME;
if(!err) {
dbObject._rev = body._rev;
}
dbObject.language = "javascript";
dbObject.views = {
a_then_b: {
map: function(doc) {
emit([doc.a, doc.b]);
}
},
b_then_a: {
map: function(doc) {
emit([doc.b, doc.a]);
}
},
};
jasonDB.insert(dbObject, function(err, body, header) {
if(err) {
console.log("insert error:");
console.log(err);
} else {
console.log("created " + "jason/_design/" + DESIGN_DOCUMENT_NAME);
}
})
} else {
console.log("get error:");
console.log(err);
}
});
}
var queryTest = function() {
jasonDB.view(
DESIGN_DOCUMENT_NAME,
"a_then_b",
{ startkey: [1, 2], endkey: [3, 2] },
function(err, body) {
if(err) {
console.log(err);
} else {
console.log("a_then_b")
body.rows.forEach(function(el) {
console.log(el);
});
console.log("body.rows.length = " + body.rows.length);
console.log("");
}
}
);
jasonDB.view(
DESIGN_DOCUMENT_NAME,
"b_then_a",
{ startkey: [2, 1], endkey: [2, 3] },
function(err, body) {
if(err) {
console.log(err);
} else {
console.log("b_then_a")
body.rows.forEach(function(el) {
console.log(el);
});
console.log("body.rows.length = " + body.rows.length);
}
}
);
}
//createTestRecords();
//createDesignDocument();
setTimeout(function() {
queryTest();
}, 1000);
输出:
a_then_b
{ id: '812f16b3826569ec94eb35d087030d64',
key: [ 1, 2 ],
value: null }
{ id: '812f16b3826569ec94eb35d087030709',
key: [ 1, 3 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702a846',
key: [ 1, 4 ],
value: null }
{ id: '812f16b3826569ec94eb35d087032077',
key: [ 2, 1 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702fd89',
key: [ 2, 2 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702caee',
key: [ 2, 3 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702c32a',
key: [ 2, 4 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702b358',
key: [ 3, 1 ],
value: null }
{ id: '812f16b3826569ec94eb35d087031386',
key: [ 3, 2 ],
value: null }
body.rows.length = 9
b_then_a
{ id: '812f16b3826569ec94eb35d087030d64',
key: [ 2, 1 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702fd89',
key: [ 2, 2 ],
value: null }
{ id: '812f16b3826569ec94eb35d087031386',
key: [ 2, 3 ],
value: null }
body.rows.length = 3
如果第二个键是索引中的第一个键,您只能这样做。所以你需要尊重索引中的键,这样 b
首先被索引, a
第二。这将允许您在 [2,1]
到 [2,3]
的范围内搜索。