QuerySet.item_frequencies works with non-list fields

This commit is contained in:
Harry Marr 2010-10-03 15:01:45 +01:00
parent 4c68bc6c96
commit 4012722a8d
2 changed files with 28 additions and 9 deletions

View File

@ -916,20 +916,27 @@ class QuerySet(object):
""" """
return self.exec_js(average_func, field) return self.exec_js(average_func, field)
def item_frequencies(self, list_field, normalize=False): def item_frequencies(self, field, normalize=False):
"""Returns a dictionary of all items present in a list field across """Returns a dictionary of all items present in a field across
the whole queried set of documents, and their corresponding frequency. the whole queried set of documents, and their corresponding frequency.
This is useful for generating tag clouds, or searching documents. This is useful for generating tag clouds, or searching documents.
:param list_field: the list field to use If the field is a :class:`~mongoengine.ListField`, the items within
each list will be counted individually.
:param field: the field to use
:param normalize: normalize the results so they add to 1.0 :param normalize: normalize the results so they add to 1.0
""" """
freq_func = """ freq_func = """
function(listField) { function(field) {
if (options.normalize) { if (options.normalize) {
var total = 0.0; var total = 0.0;
db[collection].find(query).forEach(function(doc) { db[collection].find(query).forEach(function(doc) {
total += doc[listField].length; if (doc[field].constructor == Array) {
total += doc[field].length;
} else {
total++;
}
}); });
} }
@ -939,14 +946,19 @@ class QuerySet(object):
inc /= total; inc /= total;
} }
db[collection].find(query).forEach(function(doc) { db[collection].find(query).forEach(function(doc) {
doc[listField].forEach(function(item) { if (doc[field].constructor == Array) {
doc[field].forEach(function(item) {
frequencies[item] = inc + (frequencies[item] || 0);
});
} else {
var item = doc[field];
frequencies[item] = inc + (frequencies[item] || 0); frequencies[item] = inc + (frequencies[item] || 0);
}); }
}); });
return frequencies; return frequencies;
} }
""" """
return self.exec_js(freq_func, list_field, normalize=normalize) return self.exec_js(freq_func, field, normalize=normalize)
def __repr__(self): def __repr__(self):
limit = REPR_OUTPUT_SIZE + 1 limit = REPR_OUTPUT_SIZE + 1

View File

@ -973,7 +973,7 @@ class QuerySetTest(unittest.TestCase):
BlogPost(hits=1, tags=['music', 'film', 'actors']).save() BlogPost(hits=1, tags=['music', 'film', 'actors']).save()
BlogPost(hits=2, tags=['music']).save() BlogPost(hits=2, tags=['music']).save()
BlogPost(hits=3, tags=['music', 'actors']).save() BlogPost(hits=2, tags=['music', 'actors']).save()
f = BlogPost.objects.item_frequencies('tags') f = BlogPost.objects.item_frequencies('tags')
f = dict((key, int(val)) for key, val in f.items()) f = dict((key, int(val)) for key, val in f.items())
@ -995,6 +995,13 @@ class QuerySetTest(unittest.TestCase):
self.assertAlmostEqual(f['actors'], 2.0/6.0) self.assertAlmostEqual(f['actors'], 2.0/6.0)
self.assertAlmostEqual(f['film'], 1.0/6.0) self.assertAlmostEqual(f['film'], 1.0/6.0)
# Check item_frequencies works for non-list fields
f = BlogPost.objects.item_frequencies('hits')
f = dict((key, int(val)) for key, val in f.items())
self.assertEqual(set(['1', '2']), set(f.keys()))
self.assertEqual(f['1'], 1)
self.assertEqual(f['2'], 2)
BlogPost.drop_collection() BlogPost.drop_collection()
def test_average(self): def test_average(self):