There is an elegant solution to this but be warned, this approach scales exponentially.
You were on the right track with composite keys.
if(doc.DocumentType == "productDoc" && doc.SellerID && doc.DeliverableAUWide && doc.Colour && doc.Size){
emit([doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size], null)
}
Gives you the ability to filter on all of these fields. Say you wanted all of the documents with a sellerId of 123, a DeliverableAUWide of "true", a color of red, and a size of large, just suffix your query like so.
&startkey[123,"true","red","large"]&endkey[123,"true","red","large",""]
This returns everything that matches those four validations, but your issue is that if you're utilizing this view, you must pass a value for each category.
The solution comes with CouchDB's ability to emit a row multiple times with different keys. Say you want to leave color as a wild card, if you add a new line to your map function
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)
}
you can now query like so
&startkey[123,"true",-1,"large"]&endkey[123,"true",-1,"large",""]
(note: I choose to use -1 because I assume that will never be a valid value on any of these fields. Any value can work, just make sure none of your key values on your documents will actually be whatever you choose.)
and rows with documents of all colors will be return to you. Notice that you can still use the previous query to return all red documents on this same map.
Say you want all of your filters to have the ability to be wildcards. You can use the following map function to recursively generate every emit you're looking for.
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]));
}
}
Using this map, each document will emit rows with these keys
[ 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' ]
As stated earlier, the more filters you use, the more rows you'll emit, therefor bloating your view. So please, emit responsibly.