直接,我已经读过:http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-views-writing-bestpractice.html以及Couchbase网站上的各种其他页面,但是下面的问题让我感到困扰,所以我想在推出之前仔细检查。
如果我有关于产品的文档,请说:
"DocumentType": "productDoc",
"Name": "product",
"Price": 150,
"SellerID": 10,
"DeliverableAUWide": true,
"Colour": "red",
"Size": "large"
说我想要一个介于100到200之间的产品:
if(doc.DocumentType == "productDoc" && doc.Price)
{
emit([1, doc.Price], null)
}
可以通过开始和结束键获得我想要的东西
说我也想按尺寸搜索,然后
if(doc.DocumentType == "productDoc" && doc.Size)
{
emit([2, doc.Size], null)
}
将使用正确的搜索键再次获得该信息。
说我想同时搜索两者,然后:
if(doc.DocumentType == "productDoc" && doc.Size && doc.Price)
{
emit([3, doc.Size, doc.Price], null)
}
会得到那个。
现在说我想搜索:价格,卖家ID,无论是否可交付,颜色和尺寸......
if(doc.DocumentType == "productDoc"
&& doc.Price
&& doc.SellerID
&& doc.DeliverableAUWide
&& doc.Colour
&& doc.Size
)
{
emit([4, doc.Price, doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size], null)
}
会得到那个。
但是说我也希望能够通过所有那些期望价格进行搜索,我不能使用上面的,因为Price将为null,因此其余的排放将是“无用的”,因为一切都将是匹配...
所以我需要一个新的视图查询? e.g。
if(doc.DocumentType ==“productDoc”
&& doc.SellerID
&& doc.DeliverableAUWide
&& doc.Colour
&& doc.Size
)
{
emit([5, doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size], null)
}
问题
这种方法是否正确,因为我觉得每种类型的搜索都需要一个'新'发出调用。所以在.net代码中我会查看我从用户那里搜索输入的内容然后调用右边的'emit'(注意:这就是为什么我在发出前面有数字的原因所以我可以稍后分辨它们 - - 为了理智......)。
我不仅关注我必须写的视图的长度,而且说我稍后在文档中添加了一个字段,比如'Discount Amount',然后我改变了视图,那将是重新索引是大规模还是?这是一个问题???
以上结构的可能替代方案
或者仅仅说出来更好,
if(doc.DocumentType == "productDoc" && doc.Price)
{
emit([1, doc.Price], null)
}
if(doc.DocumentType == "productDoc" && doc.Size)
{
emit([2, doc.Size], null)
}
然后当我想要按价格和尺寸调用产品并获得有效的“列表”文档ID然后“交叉”这些列表并查看两者中的ID,然后调用以获取文档。这种方法但对CB服务器的调用要多得多,而且我也无法使用内置的skip,limit和startkey_docid进行分页。这在代码方面似乎也更具性能。我认为这是Couchbase的“错误”思维方式,但是来自一个心态“对DB =更少的呼叫更好”的环境,我可能没有正确地接受CB哲学......
如果有人可以请:
那会很棒。
如果事情没有意义,请告诉我......
提前致谢,
干杯
罗宾
其他说明:此文档是存储桶中唯一的文档结构。我只有1个视图。 10k文件〜是。
答案 0 :(得分:1)
有一个优雅的解决方案,但要注意,这种方法成倍增长。
您使用复合键在正确的轨道上。
if(doc.DocumentType == "productDoc" && doc.SellerID && doc.DeliverableAUWide && doc.Colour && doc.Size){
emit([doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size], null)
}
使您能够过滤所有这些字段。假设您想要所有的文件,其SellerId为123,可交付的优先级为#34; true",红色,大小,只需后缀您的查询。
&startkey[123,"true","red","large"]&endkey[123,"true","red","large",""]
这会返回与这四种验证相匹配的所有内容,但您的问题是,如果您正在使用此视图,则必须为每个类别传递一个值。
该解决方案附带CouchDB能够使用不同的密钥多次发出一行。假设您要将颜色保留为外卡,如果向地图功能添加新行
if(doc.DocumentType == "productDoc" && doc.SellerID && doc.DeliverableAUWide && doc.Colour && doc.Size){
emit([doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size], null)
emit([doc.SellerID, doc.DeliverableAUWide, -1, doc.Size], null)
}
您现在可以这样查询
&startkey[123,"true",-1,"large"]&endkey[123,"true",-1,"large",""]
(注意:我选择使用-1,因为我认为在任何这些字段中永远不会是有效值。任何值都可以工作,只要确保文档中的任何键值都不是您选择的任何值。)
包含所有颜色文档的行将返回给您。请注意,您仍然可以使用上一个查询返回同一个地图上的所有红色文档。
假设您希望所有过滤器都能够成为通配符。您可以使用以下地图功能递归生成您正在寻找的每个发射。
function(doc, meta) {
var emitCombos = function(current) {
var dataSet = [doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size]; //add any new keys as they come up here
var current = current || [];
return (current.length === dataSet.length) ? [current] : emitCombos(current.concat(dataSet[current.length])).concat(emitCombos(current.concat(-1)));
};
var allCombos = emitCombos();
//if all three are -1, it's not really filtering, hence the ... .length-1
for (var combo = 0; combo < allCombos.length - 1; combo++) {
emit(allCombos[combo].concat(doc.document.createdDate[1]));
}
}
使用此地图,每个文档将使用这些键发出行
[ 123, 'TRUE', 'RED', 'LARGE' ]
[ 123, 'TRUE', 'RED', -1 ]
[ 123, 'TRUE', -1, 'LARGE' ]
[ 123, 'TRUE', -1, -1 ]
[ 123, -1, 'RED', 'LARGE' ]
[ 123, -1, 'RED', -1 ]
[ 123, -1, -1, 'LARGE' ]
[ 123, -1, -1, -1 ]
[ -1, 'TRUE', 'RED', 'LARGE' ]
[ -1, 'TRUE', 'RED', -1 ]
[ -1, 'TRUE', -1, 'LARGE' ]
[ -1, 'TRUE', -1, -1 ]
[ -1, -1, 'RED', 'LARGE' ]
[ -1, -1, 'RED', -1 ]
[ -1, -1, -1, 'LARGE' ]
如前所述,您使用的过滤器越多,您发出的行就越多,从而使您的视图膨胀。所以,请负责任地发出。
答案 1 :(得分:0)
1-使用复合键的第一种方法可能不符合您的要求。我之所以这么说是因为你只能从左到右查询密钥(见http://blog.couchbase.com/understanding-grouplevel-view-queries-compound-keys)
2-执行多次发射的第二种方法是一种可能的方法,但您必须小心查询以获取适当的数据范围/类型。正如您所说,如果您想添加新属性,则必须重新索引所有文档。
为什么不创建多个视图并采用相同的方法并在应用程序中执行相交?
另一种方法可能是使用Elasticsearch插件将索引委托给Elastic in以获得更复杂的全文搜索查询。 http://www.couchbase.com/docs/couchbase-elasticsearch/
PS:每个视图的大小在大多数情况下都不是问题所以不要担心这个问题。
答案 2 :(得分:0)
在Couchbase 3.x版中,您可以使用N1QL query language指定过滤条件,以便在没有任何视图的情况下选择您的json对象。
例如,您应该能够发出如下查询:
SELECT *
FROM your_bucket_name
WHERE yourID1 = 'value1' AND yourID2 = 'value2' etc...
另一种方法是利用Couchbase integration with ElasticSearch并在ElasticSearch引擎中执行搜索查询,该搜索查询将根据您的搜索条件返回它找到的所有密钥。它还通过XDCR streaming与您的存储桶同步。