Reputation: 51
I'm using pyMongo 1.11 and MongoDB 1.8.2. I'm trying to do a fairly complex Map/Reduce. I prototyped the functions in Mongo and got it working, but when I tried transferring it to Python, I get:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/Developer/R-and-D/<ipython-input-71-3c3a43221538> in <module>()
----> 1 results = db.user_actions.mapReduce(map, reduce, "user_entities_interactions")
/Library/Python/2.7/site-packages/pymongo/collection.pyc in __call__(self, *args, **kwargs)
1099 "call the '%s' method on a 'Collection' object it is "
1100 "failing because no such method exists." %
-> 1101 self.__name.split(".")[-1])
TypeError: 'Collection' object is not callable. If you meant to call the 'mapReduce' method on a 'Collection' object it is failing because no such method exists.
My collection looks like this:
{ "_id" : ObjectId("..."), "entity_id" : 1556, "user_id" : 466112 }
{ "_id" : ObjectId("..."), "entity_id" : 1366, "user_id" : 10057 }
{ "_id" : ObjectId("..."), "entity_id" : 234, "user_id" : 43650 }
{ "_id" : ObjectId("..."), "entity_id" : 6, "user_id" : 34430 }
{ "_id" : ObjectId("..."), "entity_id" : 461, "user_id" : 3416 }
{ "_id" : ObjectId("..."), "entity_id" : 994, "user_id" : 10057 }
{ "_id" : ObjectId("..."), "entity_id" : 296, "user_id" : 466112 }
The code I'm running in Python is:
map = Code("""function () {
emit(this.user_id, {
user_id : this.user_id,
entity_id : this.entity_id});
}""")
reduce = Code("""function (key, values) {
var entities = { user_id : values[0].user_id, entity_id : [ ] };
for (var i = 0; i < values.length; i++) {
entities.entity_id[i] = values[i].entity_id;
}
return entities;
}""")
results = db.user_actions.mapReduce(map, reduce, "user_entities_interactions")
What the result should look like is:
{ "_id" : 3416, "value" : { "user_id" : 3416, "entity_id" : 461 } }
{ "_id" : 10057, "value" : { "user_id" : 10057, "entity_id" : [ 1366, 994 ] } }
{ "_id" : 34430, "value" : { "user_id" : 34430, "entity_id" : 6 } }
{ "_id" : 43650, "value" : { "user_id" : 43650, "entity_id" : 234 } }
{ "_id" : 466112, "value" : { "user_id" : 466112, "entity_id" : [ 1556, 296 ] } }
I'm not clear on what the problem is. The error says that the 'Collection' object has no mapReduce method, but that's clearly not true as the example at http://api.mongodb.org/python/current/examples/map_reduce.html works and what is 'things' if not a collection?
Also, in case you're wondering why I'm not doing this with group() it's because I have more than 20000 unique keys.
Upvotes: 5
Views: 16778
Reputation: 49
One update on this, PyMongo 4.0 Removed pymongo.collection.Collection.map_reduce(). Using 4.0+ version of pymongo will give same error for map_reduce method.
Details can be found here
Upvotes: 0
Reputation: 7418
The Problem
As mentioned in all the answers, the problem is that the MapReduce method in pymongo
is actually written with underscores, i.e. map_reduce, to fit into the most used Python code style.
The Confusing Error
TypeError: 'Collection' object is not callable. If you meant to call the 'mapReduce' method on a 'Collection' object it is failing because no such method exists.
The error might seem very much confusing and take you in the wrong direction. The point here is, that MongoDB uses internal/system collection names that use a dot, e.g. system.namespaces
, system.indexes
, system.profile
, etc. Although MongoDB does not let you use a dot-ed name to create a new collection, anyway you may query existing system collections. So while you run your user_actions.mapReduce
code, it actually treats user_actions.mapReduce
as a single collection, i.e. instance of Collection object, and then tries to execute the __call__
method on that object, which does not exist. Thus the error.
The good part it is that pymongo
considers this case, and hints about the possibility that you were trying to execute the mapReduce
method on the corresponding Collection object which does not exist.
Upvotes: 2
Reputation: 53819
It's not called mapReduce
, but map_reduce
. Try:
results = db.user_actions.map_reduce(map, reduce, "user_entities_interactions")
Upvotes: 7
Reputation: 96258
read that linked page again, the method is called map_reduce
also, in that example things
is a collection, it's get created when you insert the first document in it.
Upvotes: 0