Awesome
nimongo - Pure Nim MongoDB Driver
nimongo
has a main intention to provide developer-friendly way to interact
with MongoDB using Nim programming language without any other dependencies.
You can find a table of supported features at the bottom of the document.
nimongo
is tested on MongoDB 3.x.x
and 4.0.x
versions with GCC and MSVS2017 compiler backends and the latest stable version of Nim (0.19.0).
Installation
You can use nimble
package manager to install nimongo
. The most recent
version of the library can be installed like this:
$ nimble install nimongo
or directly from Git repo:
$ nimble install https://github.com/SSPkrolik/nimongo.git
Current status (briefly)
Currently nimongo.mongo
implements connection to single MongoDB server, and
support for most widely used queries (whole CRUD with some exceptions),
nimongo.bson
gives full support of current BSON specification. As for
performance, it is comparable with pymongo
Python driver on rough timeit-style
tests.
Usage of synchronous client
nimongo.mongo.Mongo
synchronous client perform interaction with MongoDB
over network using sockets and blocking I/O which stops the thread it is
used on from executing while MongoDB operation is not finished: either data
is sent over network (insert, update, remove), or query (find) is done,
and answer (or portion of it) is waited for.
Mongo synchronous client is thread-safe. It uses simple Lock
when
executing commands and queries.
import oids
import nimongo.bson ## MongoDB BSON serialization/deserialization
import nimongo.mongo ## MongoDB client
## Create new Mongo client
var m = newMongo().slaveOk(true).allowPartial(false)
## Connect to Mongo server
let connectResult = m.connect()
## Specify collection
let collection = m["db"]["collectionName"]
## Create new bson document
let doc = %*{
"name": "John"
}
## Insert document into DB
collection.insert(doc)
## Update [single] document
let reply = collection.update(%*{
"name": "John"
}, %*{
"$set": {
"surname": "Smith"
}
})
# Check command execution status
if reply.ok:
echo "Modified a document."
## Delete multiple documents
let removeResult = collection.remove(%*{"name": "John"})
## Check how many documents were removed
if removeResult.ok:
echo "Removed ", removeResult.n, " documents."
## Delete single document
collection.remove(%{"name": "John"}, limit=1)
## Delete collection
collection.drop()
## Delete single document
collection.remove(%{"name": "John"}, limit=1)
## Fetch number of documents in collection
collection.count()
## Fetch number of documents in query
let tally = collection.find(%*{"name": "John"}).count()
## Fetch one document from DB returning only one field: "name".
let fetched = collection.find(%*{"name": "John"}, @["name"]).one()
## Fetch all matching documents from DB receiving seq[Bson]
let documents = collection.find(%*{"name": "John"}).all()
## Fetch all matching documents as a iterator
for document in collection.find(%*{"name": "John"}).items():
echo document
## Force cursor to return only distinct documents by specified field.
let documents = collection.find(%*{"name": "John"}).unique("name").all()
Usage of async client
nimongo.mongo.Mongo
can also work in an asynchronous mode based on
ayncdispatch
standard async mechanisms, and asyncnet.AsyncSocket
sockets. It
performs non-blocking I/O via {.async.}
procedures.
Mongo async client is thread-safe. It uses simple Lock
when
executing commands and queries.
import asyncdispatch ## Nim async-supportive functions here
import oids
import nimongo.bson ## MongoDB BSON serialization/deserialization
import nimongo.mongo ## MongoDB client
## Create new Mongo client
var m: AsyncMongo = newAsyncMongo().slaveOk(false) ## Still Mongo type
## Connect to Mongo server with asynchronous socket
let connected = waitFor(m.connect())
## Testing connection establishing result
echo "Async connection established: ", connected
## Inserting single document into MongoDB
waitFor(m.insert(B("hello-async", "victory")))
## Inserting multiple documents into MongoDB
let
doc1 = %*{"doc1": 15}
doc2 = %*{"doc2": "string"}
waitFor(m.insert(@[doc1, doc2]))
## Removing single document from MongoDB
waitFor(m.remove(B("doc1", 15), limit=1))
## Removing multiple documents from MongoDB
waitFor(m.remove(B("doc1", 15)))
Currently Supported Features
Here's a list of supported features with appropriate status icons:
- :white_check_mark: - implemented feature
- :red_circle: - not implemented feature
- :warning: - partly supported or unstable
BSON
nimongo.bson
module implements full BSON specification, and includes means
for developer-friendly BSON creation, modification, serialization and
deserialization.
You can user either B(...) template or %*
for documents creation
depending on what is more convenient for you.
let doc = B("name", "John")("surname", "Smith")("salary", 100)
let doc2 = B(
"name", "Sam")(
"surname", "Uncle")(
"salary", 1000)(
"skills", @["power", "government", "army"]
)
Authentication
nimongo
supports the new SCRAM-SHA-1 challenge-response user authentication mechanism
var db: Database[Mongo]
try:
db = newMongoDatabase("mongodb://$1:$2@localhost:27017/db" % [db_user,db_pass])
if not db.client.authenticated: raise newException(AUTHError, "Unable to authenticate to db")
except:
logging.error(getCurrentExceptionMsg())
raise
MongoDB Features
This table represents MongoDB features and their implementation status within
nimongo.mongo
Nim module.
Block | Feature | Status (sync) | Status (async) | Notes |
---|---|---|---|---|
Connection | 2 / 7 | 2 / 7 | ||
Single server | :white_check_mark: | :white_check_mark: | ||
Replica set | :red_circle: | :red_circle: | ||
Socket Timeout | :red_circle: | :red_circle: | ||
SSL | :red_circle: | :red_circle: | ||
Connect Timeout | :red_circle: | :red_circle: | ||
Write Concern | :white_check_mark: | :white_check_mark: | ||
Read Preference | :red_circle: | :red_circle: | ||
Operations | Insert (Single/Multiple), Remove (Single/Multiple), Update (Single/Multiple/Upsert) | :white_check_mark: | :white_check_mark: | |
Querying | 6 / 10 | 5 / 9 | ||
Find one | :white_check_mark: | :white_check_mark: | ||
Find all | :white_check_mark: | :white_check_mark: | ||
Find iterator | :white_check_mark: | :white_check_mark: | ||
Skip | :white_check_mark: | :white_check_mark: | ||
Limit | :white_check_mark: | :white_check_mark: | ||
Count | :white_check_mark: | :white_check_mark: | ||
Tailable | :white_check_mark: | :white_check_mark: | ||
Partial | :red_circle: | :red_circle: | ||
FindAndModify | :red_circle: | :red_circle: | ||
parallelCollectionScan | :red_circle: | :red_circle: | ||
getLastError | :white_check_mark: | :white_check_mark: | ||
Authentication | 1 / 7 | 1 / 7 | ||
authenticate | :red_circle: | :red_circle: | ||
SCRAM-SHA-1 | :white_check_mark: | :white_check_mark: | ||
MONGODB-CR | :red_circle: | :red_circle: | ||
MONGODB-X509 | :red_circle: | :red_circle: | ||
GSSAPI (Kerberos) | :red_circle: | :red_circle: | ||
PLAIN (LDAP SASL) | :red_circle: | :red_circle: | ||
logout | :red_circle: | :red_circle: | ||
User Management | 2 / 7 | 2 / 7 | ||
Create User | :white_check_mark: | :white_check_mark: | ||
Update User | :red_circle: | :red_circle: | ||
Drop User | :white_check_mark: | :white_check_mark: | ||
Drop all users | :red_circle: | :red_circle: | ||
Grant roles | :red_circle: | :red_circle: | ||
Revoke roles | :red_circle: | :red_circle: | ||
Users info | :red_circle: | :red_circle: | ||
Role Management | 0 / 0 | 0 / 0 | ||
Replication | 1 / 1 | 1 / 1 | ||
Is Master | :white_check_mark: | :white_check_mark: | ||
Sharding | 0 / 0 | 0 / 0 | ||
Instance Administration Commands | 6 / 7 | 6 / 7 | ||
Copy DB | :red_circle: | :red_circle: | ||
List databases | :white_check_mark: | :white_check_mark: | ||
Drop database | :white_check_mark: | :white_check_mark: | ||
List collections | :white_check_mark: | :white_check_mark: | ||
Rename collection | :white_check_mark: | :white_check_mark: | ||
Drop collection | :white_check_mark: | :white_check_mark: | ||
Create collection | :white_check_mark: | :white_check_mark: | ||
Diagnostic | 0 / 0 | 0 / 0 | ||
GridFS | 0 / 0 | 0 / 0 | ||
Indices | 0 / 4 | 0 / 4 | ||
Create Index | :red_circle: | :red_circle: | ||
Drop Index | :red_circle: | :red_circle: | ||
Drop Indices | :red_circle: | :red_circle: | ||
Ensure Index | :red_circle: | :red_circle: | ||
Aggregation | 3 / 6 | 3 / 6 | ||
aggregate | :red_circle: | :red_circle: | ||
count | :white_check_mark: | :white_check_mark: | ||
distinct | :white_check_mark: | :white_check_mark: | Cursor.unique proc | |
group | :red_circle: | :red_circle: | ||
mapReduce | :red_circle: | :red_circle: | ||
orderBy | :white_check_mark: | :white_check_mark: | ||
Geospatial | 0 /3 | 0 / 3 | ||
geoNear | :red_circle: | :red_circle: | ||
geoSearch | :red_circle: | :red_circle: | ||
geoWalk | :red_circle: | :red_circle: | ||
Auditing | 0 / 1 | 0 / 1 | ||
logApplicationMessage | :red_circle: | :red_circle: |
P.S. Contribution is welcomed :)