Skip to content

Commit f9243f0

Browse files
committed
PYTHON-821 - Implement insert_many
1 parent 4d6bdb1 commit f9243f0

File tree

3 files changed

+93
-2
lines changed

3 files changed

+93
-2
lines changed

pymongo/collection.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from pymongo import (common,
3030
helpers,
3131
message)
32-
from pymongo.bulk import (BulkOperationBuilder, _Bulk)
32+
from pymongo.bulk import BulkOperationBuilder, _Bulk
3333
from pymongo.command_cursor import CommandCursor
3434
from pymongo.cursor import Cursor
3535
from pymongo.errors import ConfigurationError, InvalidName, OperationFailure
@@ -495,6 +495,39 @@ def insert_one(self, document):
495495
return InsertOneResult(self.__insert(document),
496496
self.write_concern.acknowledged)
497497

498+
def insert_many(self, documents, ordered=True):
499+
"""Insert a list of documents.
500+
501+
:Parameters:
502+
- `documents`: A list of documents to insert.
503+
- `ordered` (optional): If ``True`` (the default) documents will be
504+
inserted on the server serially, in the order provided. If an error
505+
occurs all remaining inserts are aborted. If ``False``, documents
506+
will be inserted on the server in arbitrary order, possibly in
507+
parallel, and all document inserts will be attempted.
508+
509+
:Returns:
510+
An instance of :class:`~pymongo.results.InsertManyResult`.
511+
"""
512+
if not isinstance(documents, list) or not documents:
513+
raise TypeError("documents must be a non-empty list")
514+
inserted_ids = []
515+
def gen():
516+
"""A generator that validates documents and handles _ids."""
517+
for document in documents:
518+
if not isinstance(document, collections.MutableMapping):
519+
raise TypeError("document must be a dict or other "
520+
"subclass of collections.MutableMapping")
521+
if "_id" not in document:
522+
document["_id"] = ObjectId()
523+
inserted_ids.append(document["_id"])
524+
yield (_INSERT, document)
525+
526+
blk = _Bulk(self, ordered)
527+
blk.ops = [doc for doc in gen()]
528+
blk.execute(self.write_concern.document)
529+
return InsertManyResult(inserted_ids, self.write_concern.acknowledged)
530+
498531
def __insert(self, docs, ordered=True,
499532
check_keys=True, manipulate=False, write_concern=None):
500533
"""Internal insert helper."""

pymongo/results.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,28 @@ def inserted_id(self):
5252
return self.__inserted_id
5353

5454

55+
class InsertManyResult(_WriteResult):
56+
"""The return type for :meth:`~pymongo.collection.Collection.insert_many`.
57+
"""
58+
59+
__slots__ = ("__inserted_ids", "__acknowledged")
60+
61+
def __init__(self, inserted_ids, acknowledged):
62+
self.__inserted_ids = inserted_ids
63+
super(InsertManyResult, self).__init__(acknowledged)
64+
65+
@property
66+
def inserted_ids(self):
67+
"""A list of _ids of the inserted documents, in the order provided.
68+
69+
.. note:: If ``False`` is passed for the `ordered` parameter to
70+
:meth:`~pymongo.collection.Collection.insert_many` the server
71+
may have inserted the documents in a different order than what
72+
is presented here.
73+
"""
74+
return self.__inserted_ids
75+
76+
5577
class UpdateResult(_WriteResult):
5678
"""The return type for :meth:`~pymongo.collection.Collection.update_one`
5779
and :meth:`~pymongo.collection.Collection.update_many`"""

test/test_collection.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
WTimeoutError)
4949
from pymongo.options import ReturnDocument
5050
from pymongo.read_preferences import ReadPreference
51-
from pymongo.results import DeleteResult, InsertOneResult, UpdateResult
51+
from pymongo.results import *
5252
from pymongo.son_manipulator import SONManipulator
5353
from pymongo.write_concern import WriteConcern
5454
from test.test_client import IntegrationTest
@@ -639,6 +639,42 @@ def test_insert_one(self):
639639
# The insert failed duplicate key...
640640
self.assertEqual(2, db.test.count())
641641

642+
def test_insert_many(self):
643+
db = self.db
644+
db.test.drop()
645+
646+
docs = [{} for _ in range(5)]
647+
result = db.test.insert_many(docs)
648+
self.assertTrue(isinstance(result, InsertManyResult))
649+
self.assertTrue(isinstance(result.inserted_ids, list))
650+
self.assertEqual(5, len(result.inserted_ids))
651+
for doc in docs:
652+
_id = doc["_id"]
653+
self.assertTrue(isinstance(_id, ObjectId))
654+
self.assertTrue(_id in result.inserted_ids)
655+
self.assertEqual(1, db.test.count({'_id': _id}))
656+
self.assertTrue(result.acknowledged)
657+
658+
docs = [{"_id": i} for i in range(5)]
659+
result = db.test.insert_many(docs)
660+
self.assertTrue(isinstance(result, InsertManyResult))
661+
self.assertTrue(isinstance(result.inserted_ids, list))
662+
self.assertEqual(5, len(result.inserted_ids))
663+
for doc in docs:
664+
_id = doc["_id"]
665+
self.assertTrue(isinstance(_id, int))
666+
self.assertTrue(_id in result.inserted_ids)
667+
self.assertEqual(1, db.test.count({"_id": _id}))
668+
self.assertTrue(result.acknowledged)
669+
670+
db = db.connection.get_database(db.name,
671+
write_concern=WriteConcern(w=0))
672+
docs = [{} for _ in range(5)]
673+
result = db.test.insert_many(docs)
674+
self.assertTrue(isinstance(result, InsertManyResult))
675+
self.assertFalse(result.acknowledged)
676+
self.assertEqual(15, db.test.count())
677+
642678
def test_generator_insert(self):
643679
db = self.db
644680
db.test.remove({})

0 commit comments

Comments
 (0)