couchdb - problems grouping collections
I'm having problems trying to get my head around getting a collection of types along with number of times a skill is found in that doc type.
There are a number of document types that have a list of skills.
{
"skills": "Windows, Network Admin, Linux",
"type": "Experience"
},
{
"skills": "Windows, Erlang, Linux",
"type": "Experience"
},
{
"skills": "Ruby, Rails, Erlang",
"type": "Project"
}
I'm trying to get the number of times a skill is found in an document type.
The end result should look something like this:
{
'type': Experience,
'skills': [
{'skill': 'Erlang', 'count': 1},
{'skill': 'Linux', 'count': 2},
{'skill': 'Network Admin', 'count': 1},
{'skill': 'Rails', 'count': 0},
{'skill': 'Ruby', 'count': 0},
{'skill': 'Windows', 'count': 2}
]
},
{
'type': Project,
'skills': [
{'skill': 'Erlang', 'count': 1},
开发者_JAVA技巧{'skill': 'Linux', 'count': 0},
{'skill': 'Network Admin', 'count': 0},
{'skill': 'Rails', 'count': 1},
{'skill': 'Ruby', 'count': 1},
{'skill': 'Windows', 'count': 0}
]
}
What would be the best way to do this?
You should store the skill list in your docs as a real list.
{
"skills": ["Windows", "Network Admin", Linux"],
"type": "Experience"
}
From there, your map function becomes:
function(doc) {
for(var skill in doc.skills) {
emit([doc.type, skill], 1);
}
}
And the reduce function just sums the result, so use "_sum". You can easily choose to show only Experience or Project with start and end keys.
Here are map and reduce functions (view named skill_split
) and a list function that will produce output close to what you asked for using a URL like this http://127.0.0.1:5984/myskills/_design/myskills/_list/transform/skill_split?group=true
:
{
"Experience": {"Erlang":1, "Linux":2, "Network Admin":1, "Windows":2},
"Project":{"Erlang":1, "Rails":1, "Ruby":1}
}
I can tweak the code to make the output exactly what you asked for, but the list function would be a bit longer.
map:
function(doc) {
if (doc.type && doc.skills) {
doc.skills.split(', ').forEach(function(skill) {
emit([doc.type, skill], 1);
});
}
}
reduce:
function(keys, values, rereduce) {
return sum(values)
}
or use "reduce": "_sum"
for short
list (named transform
):
function(head, req) {
var results = {};
var row;
while (row = getRow()) {
var skill_map;
if (results.hasOwnProperty(row.key[0])) {
skill_map = results[row.key[0]];
} else {
skill_map = {};
results[row.key[0]] = skill_map;
}
if (skill_map.hasOwnProperty(row.key[1])) {
skill_map[row.key[1]] = skill_map[row.key[1]] + row.value;
} else {
skill_map[row.key[1]] = row.value;
}
}
send(JSON.stringify(results));
}
If you don't have access to the JSON object (you do inside a CouchApp), you might have to jump through some hoops to get access to it.
精彩评论