Native MongoDB driver for Swift, written in Swift

Overview

OpenKitten

OpenKitten

Installation | Tutorial | Basic usage | About BSON | Codable | Community | How to help

A fast, pure swift MongoDB driver based on Swift NIO built for Server Side Swift. It features a great API and a battle-tested core. Supporting both MongoDB in server and embedded environments.

⭐️ Please leave a star to support MongoKitten – it really helps!

🐈 Community & Docs

Join our Discord for any questions and friendly banter.

Read the Docs at our sponsor's website.

Projects

A couple of MongoKitten based projects have arisen, check them out!

🤝 How to help

Support MongoKitten development

You can sponsor the creator via GitHub.. This enables us to provide a higher quality and more documentation as well as building more tools.

Backers

The App

MongoKitten App can help you browse your dataset, support customers and debug complex aggregates.

The Company

MongoKitten is developed by Orlandos. Hire us!

Contribute to MongoKitten

  • Donate so that we can spend more time on improving the docs.
  • See CONTRIBUTING.md for info on contributing to MongoKitten
  • You can help us out by resolving TODOs and replying on issues
  • Of course, all feedback, positive and negative, also really helps to improve the project

🕶 Installation

Set up MongoDB server

If you haven't already, you should set up a MongoDB server to get started with MongoKitten

For development, this can be on your local machine.

Install MongoDB for Ubuntu, macOS or any other supported Linux Distro.

Alternatively, make use of a DAAS (Database-as-a-service) like MongoDB Atlas, MLab, IBM Cloud or any other of the many services.

Add MongoKitten to your Swift project 🚀

If you're using a SwiftNIO 1.x framework such as Vapor 3, use MongoKitten 5 instead.

MongoKitten supports the Swift Package Manager for server-side applications. Add MongoKitten to your dependencies in your Package.swift file:

.package(url: "https://github.com/OpenKitten/MongoKitten.git", from: "6.0.0")

Also, don't forget to add "MongoKitten" as a dependency for your target.

FAQ

I can't connect to MongoDB, authentication fails!
  1. Make sure you've specified authSource=admin, unless you know what your authSource is. MongoDB's default value is really confusing.
  2. If you've specified an authMechanism, try removing it. MongoKitten can detect the correct one automatically.

🚲 Basic usage

Check out my Ray Wenderlich Article to learn the basics!

Connect to your database

import MongoKitten

let db = try MongoDatabase.synchronousConnect("mongodb://localhost/my_database")

Vapor users should register the database as a service.

extension Request {
    public var mongoDB: MongoDatabase {
        return application.mongoDB.hopped(to: eventLoop)
    }
    
    // For Meow users only
    public var meow: MeowDatabase {
        return MeowDatabase(mongoDB)
    }
    
    // For Meow users only
    public func meow<M: ReadableModel>(_ type: M.Type) -> MeowCollection<M> {
        return meow[type]
    }
}

private struct MongoDBStorageKey: StorageKey {
    typealias Value = MongoDatabase
}

extension Application {
    public var mongoDB: MongoDatabase {
        get {
            storage[MongoDBStorageKey.self]!
        }
        set {
            storage[MongoDBStorageKey.self] = newValue
        }
    }
    
    // For Meow users only
    public var meow: MeowDatabase {
        MeowDatabase(mongoDB)
    }
    
    public func initializeMongoDB(connectionString: String) throws {
        self.mongoDB = try MongoDatabase.lazyConnect(connectionString, on: self.eventLoopGroup)
    }
}

And make sure to call app.initializeMongoDB!

NIO Futures

MongoKitten relies on Swift NIO to provide support for asynchronous operations. All MongoKitten operations that talk to the server are asynchronous, and return an EventLoopFuture of some kind.

You can learn all about NIO by reading its readme or the article on RayWenderlich.com, but here are the basics:

Asynchronous operations return a future. NIO implements futures in the EventLoopFuture<T> type. An EventLoopFuture is a holder for a result that will be provided later. The result of the future can either be successful yielding a result of T, or unsuccessful with a result of a Swift Error. This is the asynchronous representation of a successful return or a thrown error.

If you're using Vapor 4, please refer to their Async documentation. Vapor's Async module provides additional helpers on top of NIO, that make working with instances of EventLoopFuture<T> easier.

If you use Vapor or another Swift-NIO based web framework, never use the wait() function on EventLoopFuture instances.

CRUD (Create, Read, Update, Delete)

// The collection "users" in your database
let users = db["users"]

Create (insert)

let myUser: Document = ["username": "kitty", "password": "meow"]

let future: EventLoopFuture<InsertReply> = users.insert(myUser)

future.whenSuccess { _ in
	print("Inserted!")
}

future.whenFailure { error in
	print("Insertion failed", error)
}

Read (find) and the query builder

To perform the following query in MongoDB:

{
	"username": "kitty"
}

Use the following MongoKitten code:

users.findOne("username" == "kitty").whenSuccess { (user: Document?) in
	// Do something with kitty
}

To perform the following query in MongoDB:

{
	"$or": [
		{ "age": { "$lte": 16 } },
		{ "age": { "$exists": false } }
	]
}

Use the following MongoKitten code:

users.find("age" <= 16 || "age" == nil).forEach { (user: Document) in
	// Print the user's name
	print(user["username"] as? String)
}

You can also type out the queries yourself, without using the query builder, like this:

users.findOne(["username": "kitty"])

Cursors

Find operations return a Cursor. A cursor is a pointer to the result set of a query. You can obtain the results from a cursor by iterating over the results, or by fetching one or all of the results.

Fetching results

You can fetch all results as an array:

let results: EventLoopFuture<[Document]> = users.find().getAllResults()

Note that this is potentially dangerous with very large result sets. Only use getAllResults() when you are sure that the entire result set of your query fits comfortably in memory.

Iterating over results

For more efficient handling of results, you can lazily iterate over a cursor:

let doneIterating: EventLoopFuture<Void> = users.find().forEach { (user: Document) in
	// ...
}
Cursors are generic

Find operations return a FindCursor<Document>. As you can see, FindCursor is a generic type. You can lazily transform the cursor into a different result type by using map, which works similar to map on arrays or documents:

users.find()
	.map { document in
		return document["username"] as? String
	}
	.forEach { username: String? in
		print("user: \(username)")
	}

Update

users.updateMany(where: "username" == "kitty", setting: ["age": 3]).whenSuccess { _ in
	print("🐈")
}

Delete

users.deleteOne(where: "username" == "kitty").whenSuccess { reply in
	print("Deleted \(reply.deletes) kitties 😿")
}

📦 About BSON & Documents

MongoDB is a document database that uses BSON under the hood to store JSON-like data. MongoKitten implements the BSON specification in its companion project, OpenKitten/BSON. You can find out more about our BSON implementation in the separate BSON repository, but here are the basics:

Literals

You normally create BSON Documents like this:

let documentA: Document = ["_id": ObjectId(), "username": "kitty", "password": "meow"]
let documentB: Document = ["kitty", 4]

From the example above, we can learn a few things:

  • A BSON document can represent an array or a dictionary
  • You can initialize a document like you initialize normal dictionaries and arrays, using literals
  • The values in a Document (either the array elements or the values of a dictionary pair) can be of any BSON primitive type
  • BSON primitives include core Swift types like Int, String, Double and Bool, as well as Date from Foundation
  • BSON also features some unique types, like ObjectId

Just another collection

Like normal arrays and dictionaries, Document conforms to the Collection protocol. Because of this, you can often directly work with your Document, using the APIs you already know from Array and Dictionary. For example, you can iterate over a document using a for loop:

for (key, value) in documentA {
	// ...
}

for value in documentB.values {
	// ...
}

Document also provides subscripts to access individual elements. The subscripts return values of the type Primitive?, so you probably need to cast them using as? before using them.

let username = documentA["username"] as? String

Think twice before converting between Document and Dictionary

Our Document type is implemented in an optimized, efficient way and provides many useful features to read and manipulate data, including features not present on the Swift Dictionary type. On top of that, Document also implements most APIs present on Dictionary, so there is very little learning curve.

💾 Codable

MongoKitten supports the Encodable and Decodable (Codable) protocols by providing the BSONEncoder and BSONDecoder types. Working with our encoders and decoders is very similar to working with the Foundation JSONEncoder and JSONDecoder classes, with the difference being that BSONEncoder produces instances of Document and BSONDecoder accepts instances of Document, instead of Data.

For example, say we want to code the following struct:

struct User: Codable {
	var profile: Profile?
	var username: String
	var password: String
	var age: Int?
	
	struct Profile: Codable {
		var profilePicture: Data?
		var firstName: String
		var lastName: String
	}
}

We can encode and decode instances like this:

let user: User = ...

let encoder = BSONEncoder()
let encoded: Document = try encoder.encode(user)

let decoder = BSONDecoder()
let decoded: User = try decoder.decode(User.self, from: encoded)

A few notes:

  • BSONEncoder and BSONDecoder work very similar to other encoders and decoders
  • Nested types can also be encoded and are encouraged
    • Nested structs and classes are most often encoded as embedded documents
  • You can customize the representations using encoding/decoding strategies

Codable and cursors

When doing a find query, the Cursor's results can be transformed lazily. Lazy mapping is much more efficient than keeping the entire result set in memory as it allows for forEach- loops to be leveraged efficiently reducing the memory pressure of your application. You can leverage cursors using Codable as well.

// Find all and decode each Document lazily as a `User` type
users.find().decode(User.self).forEach { user in
	print(user.username)
}

☠️ License

MongoKitten is licensed under the MIT license.

Issues
  • Cannot create dynamic Document for arrays and nested jsons

    Cannot create dynamic Document for arrays and nested jsons

    var username = "mongo"
    var array = [1,2,3,4]
    var dict = ["name": "kitten", "type": "cat"]
    
    let userCollection = database["users"]
    
    let userDocument: Document = [
                "username":  .string(username),
                "array": .array(arr),
                "dictionary": .array(dict),
            ]
    
    try userCollection.insert(userDocument)
    
    error: cannot convert value of type '[Int]' to expected argument type 'Document'
                  array: .array(array),
                                ^~~~~
    

    Why do you need Document type and why can't we create it dynamically?

    Please provide JSON or Dictionary datatype support for queries in mongodb or atleast provide raw query support so that we can use raw strings to query mongo database

    opened by sujaykakkad 50
  • Not returning error when index clash

    Not returning error when index clash

    When a collection has a unique index and I try to add an object which would clash with an existing object, MongoKitten does not throw an error, but the object is not added.

    Steps to reproduce:

    1. Create a database with a unique index on a field (in the example it is field "value")
    {
      "unique": true,
      "key": { "value": 1 }
    }
    
    1. Add an object with value "A"
    let document: MongoKitten.Document = [
          "value": "A"
    ]
    try MongoManager.database["tests"].insert(document)
    
    1. Verify document was inserted
    [{"value":"A","_id":"bb964958d7260b8fbaf1a0e8"}]
    
    1. Add a second object with value "A"
    let document: MongoKitten.Document = [
          "value": "A"
    ]
    try MongoManager.database["tests"].insert(document)
    
    1. Verify document was inserted (fails, only original document exists, but no error thrown by MongoKitten)
    [{"value":"A","_id":"bb964958d7260b8fbaf1a0e8"}]
    

    Other details

    If this same steps are done directly in mongo an error is returned as expected.

    bug 
    opened by gabriellanata 26
  • cant connect mlab replicaset

    cant connect mlab replicaset

    this example is my problem server = try Server("mongodb://heroku_xxxxx:[email protected]:23372,serveraddress-a1.mlab.com:23372/xxxxxxx?replicaSet=rs-xxxxxx", automatically: true) thow error, MongoDB is not available on the given host and port Socket failed with code 61 ("No data available") [connectFailed] "Unknown error"

    enhancement help wanted 
    opened by sezgin 23
  • Failed to compile

    Failed to compile

    Package.swift

    import PackageDescription
    
    let package = Package(
        name: "daemon",
        dependencies: [
            .Package(url: "https://github.com/vapor/vapor.git", majorVersion: 1),
            .Package(url: "https://github.com/OpenKitten/MongoKitten.git", majorVersion: 2)
        ],
        exclude: [
            "Config",
            "Database",
            "Localization",
            "Public",
            "Resources",
            "Tests",
        ]
    )
    

    I'm trying to build template project which vapor generates. The only change I'm doing is adding dependency to beta MongoKitten. With this dependency it fails to build on Ubuntu. Compiler fails with the following error:

    /whatever/daemon/Packages/CryptoKitten-0.0.0/Sources/Cryptography/SHA1/SHA1.swift:200:18: error: expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
            hashCode = [
            ~~~~~~~~~^~~
    

    Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-38-generic x86_64) Vapor Toolbox v1.0.3 Swift version 3.0-dev (LLVM b9bd56d1b8, Clang 23f1b289cf, Swift edd2ecdf0c) Target: x86_64-unknown-linux-gnu

    bug 
    opened by pkcs12 21
  • Mongo Cursor Iteration is very slow

    Mongo Cursor Iteration is very slow

    Ok I have a collection which has over 100000 documents. I just want to iterate over the all documents once So I wrote a simple program to iterate

    import MongoKitten
    import Foundation
    
    let server = try Server(mongoURL: "mongodb://localhost")
    let database = server["samespace_dev"]
    
    let now = Date()
    let cursor = try database["collection"].find()
    
    var arr: [Document] = []
    for document in cursor{
        arr.append(document)
    }
    
    print(Date().timeIntervalSince(now))
    

    I just printed the start time and end time. The iteration took over 186 seconds(over 3 minutes). I guess the driver is converting to document type everytime which is making iteration slow. Is there a faster way to iterate. I just ran a basic find query in node and it took only 5 seconds. I just want to take documents from one collection do some changes and insert to another collection.

    opened by sujaykakkad 21
  • Insert of multiple documents with errors

    Insert of multiple documents with errors

    The insert method won't return any object ids, if a duplicate key error happens, but it throws an error.

    This behaviour would be acceptable if the stoppingOnError parameter is true, but this parameter suggests that if the insertion contains a "bad object", the work continues, and the result outcome should be the array of the inserted identifiers.

    do {
        let identifiers = try collection.insert(documents, stoppingOnError: false)
    }
    catch {
        //this is gona be called... :(
        print(error) 
    }
    

    Is is possible to get back the inserted identifiers after the error happens?

    The ideal solution would be to alternate the insert function behaviour, and check the stoppingOnError property & handle the outcome according to it. Does this make any sense or am I missing something?

    opened by tib 20
  • Exporting large number of documents cause memory problem

    Exporting large number of documents cause memory problem

    Hello!

    I'm trying to export a large number of documents. But getting memory exhausted error. What I'm doing wrong? Do I need to clear something on each iteration?

    func testExport() {
        
        let server = try! Server("mongodb://176.112.204.83:27017")
        
        let database = server["test-db"]
        let collection = database["images"]
        
        let documents: MongoKitten.CollectionSlice<BSON.Document> = try! collection.find()
        
        while let document = documents.next() {
            
            print("DOC: " + document.makeExtendedJSONString(typeSafe: true))
        }
        
        print("Done")
    }
    
    opened by bushev 20
  • Cursor timeouts

    Cursor timeouts

    I get hit with this fatal error: Error fetching extra data from the server in MongoKitten.Cursor<heroku_6pxt0cxh.browseitems> with error: timeout: file /tmp/build_0e4a544672ea566050f30beb848fe070/Packages/MongoKitten-1.7.0/Sources/MongoKitten/Cursor.swift, line 79

    Doesn't matter, happens on both read and writes.

    I suspect it's related to https://jira.mongodb.org/browse/SERVER-8188

    Any takes?

    bug 
    opened by seivan 17
  • [v6] Can't fetch more than 100 items

    [v6] Can't fetch more than 100 items

    I have the following code working with v5:

         do {
            let db = try Database.synchronousConnect(mongo_link)
            
            let collection = db[collection_name]
            collection.find().forEach {
                debugPrint("Adding \($0)")
            }.wait()
    
        }
        catch {
            debugPrint("Unexpected error: \(error).")
        }
    

    Now, when I try to do the same with v6 it doesn't work... as it crash. If I omit the .wait() I get only the first 100 entries.

         do {
            let db = try MongoDatabase.synchronousConnect(mongo_link)
            
            let collection = db[collection_name]
            collection.find().forEach {
                debugPrint("Adding \($0)")
            }
           //.wait() <--- crash 
    
        }
        catch {
            debugPrint("Unexpected error: \(error).")
        }
    
    help wanted question 
    opened by vim-zz 16
  • Value of type 'UnsafePointer<Any>' has no member 'reversed'

    Value of type 'UnsafePointer' has no member 'reversed'

    Using the brand new XCode Version 9.3 (9E145):

    In CRUD.swift, in func insert(documents:ordered:writeConcern:timeout:connection:), inside the nested func throwErrors() I am getting the error "Value of type 'UnsafePointer' has no member 'reversed'" on the line for position in positions.reversed()

    It seems that the compiler is having trouble inferring the correct value type for that line, which looks to be Array<InsertErrors.InsertError> and not UnsafePointer<Any>

    This issue has been seen before in the earlier, now-closed issue https://github.com/OpenKitten/MongoKitten/issues/101

    Any workarounds or changes I can make? I just installed MongoKitten today after updating my XCode, so i don't know if this is traceable to the new XCode 9.3/Swift 4.1 or not.

    opened by natebirkholz 15
  • Async/await helpers

    Async/await helpers

    opened by Joannis 0
  • Basic support for CosmosDB

    Basic support for CosmosDB

    I hope nobody wants this in practice. This is a hell to support, and frankly, even if I implement the support I don't want to test against this target. More info: https://github.com/vapor/fluent-mongo-driver/issues/42

    opened by Joannis 0
  • Use Double vs Int for geoNear parameters.

    Use Double vs Int for geoNear parameters.

    Is your feature request related to a problem? Please describe. The geoNear aggregate stage should accept Doubles for its parameters maxDistance, minDistance and distanceMultiplier. This way if you're doing any division for converting between units of distance it's not just rounded out to 0 and it looks like no documents match.

    Describe the solution you'd like Replace the geoNear aggregate stage to accept Doubles vs Int for maxDistance, minDistance and distanceMultiplier

    The existing implementation could also be marked as @depricated to prevent breaking changes.

    enhancement help wanted 
    opened by Andrewangeta 0
  • Jo broader connection support

    Jo broader connection support

    When used with NIOTS, this PR can be used to introduce Network.framework support. This PR also allows other custom channels to be used, for example for use with a proxy.

    In addition, this PR introduces access to the cache used by MongoKitten to enable quicker connections.

    TODO:

    • [ ] Implement a form of buildConnection in the MongoCluster
    • [ ] Rename Credentials to CachedMongoCredentials
    opened by Joannis 0
  • Added delete helpers that support multiple delete commands.

    Added delete helpers that support multiple delete commands.

    Description

    This PR adds 2 new helpers on the MongoCollection (deleteMany(...) and deleteOne(...)) type that allows specifying multiple Delete operations to perform.

    let d1 = DeleteCommand.Removal(where: ["_id": 1])
    let d2 = DeleteCommand.Removal(where: ["_id": 2])
    let d3 = DeleteCommand.Removal(where: ["_id": 3])
    ...
    collection.deleteMany([d1, d2, d3])
    
    let d1 = DeleteCommand.Removal(where: ["_id": 1])
    ...
    collection.deleteOne(d1)
    

    Motivation and Context

    This gives more flexibility to take advantage of the DeleteCommand

    How Has This Been Tested?

    It hasn't but it shouldn't have any side effects.

    Checklist:

    • [ ] If applicable, I have updated the documentation accordingly.
    • [ ] If applicable, I have added tests to cover my changes.
    opened by Andrewangeta 0
  • Implement Meow.Reference as a property wrapper

    Implement Meow.Reference as a property wrapper

    enhancement 
    opened by Joannis 0
  • Feature/docs and cleanup

    Feature/docs and cleanup

    opened by Joannis 0
  • Decode MongoDB Command Errors as MongoDBGenericErrorReply

    Decode MongoDB Command Errors as MongoDBGenericErrorReply

    Is your feature request related to a problem? Please describe. Debugging queries can be painful since you don't get to see the cause of thhe error.

    Describe the solution you'd like When the ok field is 0, decode an error instead.

    enhancement help wanted 
    opened by Joannis 0
  • Support for Geospatial Queries?

    Support for Geospatial Queries?

    Hi! Is there a way to perform GeoSpatial queries in the current version? I've seen the GeoNearOptions struct in the docs, but it guess it didn't make it to the last version... Thanks for your effort!

    opened by micyxcv 2
  • Property wrapper for references

    Property wrapper for references

    I think @Joannis knows what this means

    enhancement help wanted 
    opened by Obbut 0
Releases(6.6.3)
  • 6.6.3(Aug 25, 2020)

    1. This release contains a bugfix in a helper that would cause findAndRemove operations to result in a failure.
    2. A lot of new tests have been added in this release
    3. A low-level optimisation has been added, which will result in a lower performance for each message sent to MongoDB.

    BSON

    While updating MongoKitten is great, we've also made a huge step in the BSON library. The new BSON release has seen improved performance up to 150x faster in regular usage.

    Source code(tar.gz)
    Source code(zip)
  • 6.6.2(Aug 8, 2020)

  • 6.6.0(Jun 19, 2020)

  • 6.5.2(Jun 3, 2020)

    Before this release, there was a small chance that disconnecting the cluster would crash because of a simultaneous access with cluster discovery.

    Source code(tar.gz)
    Source code(zip)
  • 6.5.1(May 30, 2020)

  • 6.5.0(May 4, 2020)

  • 6.4.0(May 3, 2020)

  • 6.2.0(Mar 11, 2020)

  • 6.1.0(Mar 6, 2020)

  • 6.0.3(Nov 20, 2019)

    • Actually released the code meant for 6.0.2
    • Updated Meow to support models as readable or mutable, so that you can have a read-only interface into your models
    • Support hopping EventLoops on the MongoDatabase and MongoCollection types
    Source code(tar.gz)
    Source code(zip)
  • 6.0.2(Nov 11, 2019)

  • 6.0.0(Aug 18, 2019)

  • 5.1.11(Apr 15, 2019)

  • 5.1.10(Apr 8, 2019)

  • 5.1.9(Apr 8, 2019)

  • 5.1.8(Mar 21, 2019)

  • 5.1.7(Mar 18, 2019)

  • 5.1.6(Mar 14, 2019)

  • 5.1.5(Mar 6, 2019)

  • 5.1.4(Feb 28, 2019)

    • Fixed the fix that didn't completely fix the last bug
    • Also fixed another bug in the FindCursor that was doing too many cursor requests if the cursor was already drained the first time
    Source code(tar.gz)
    Source code(zip)
  • 5.1.3(Feb 28, 2019)

    General:

    • Fixed a bug where the wrong requestID was used on a cluster which would occur when requests occurred rapidly to the same host

    Mobile:

    • Support iOS 11
    Source code(tar.gz)
    Source code(zip)
  • 5.1.2(Feb 25, 2019)

  • 5.1.1(Feb 21, 2019)

  • 5.1.0(Feb 5, 2019)

    This update we're bringing you a new and often requested feature of lazily connecting. It's not the same as synchronous connect, since it does still connect asynchronously. But lazy connect will only start a MongoDB connection once the first query is being sent to MongoKitten. This way you can use an initializer like you could in MongoKitten 4, but with the performance and NIO-ness of MongoKitten 5.

    let database = try Database.lazyConnect("mongodb://localhost", on: eventLoop)
    

    Next, we're adding transactions to MongoKitten.

    let transactionDB: TransactionDatabase = try database.startTransaction(with: SessionOptions())
    let kittens: TransactionCollection = transactionDB["kittens"]
    try kittens.insert(["name": "Mongo"]).then { insert in
      return kittens.commit()
    }
    

    kittens is a normal MongoKitten.Collection (subclass), but not all operations may be allowed within a transaction as they are within a normal collection. Also; don't use the TransactionCollection after your transaction is completed/aborted. They're not a replacement for Collection.

    You can use a TransactionDatabase like a normal Database, but only for the duration of the transaction and for queries that are part of a transaction.

    Finally we've added listDatabases() on top of Cluster..

    try database.cluster.listDatabases()
    

    ..and we've added listCollections again

    try database.listCollections()
    
    Source code(tar.gz)
    Source code(zip)
  • 5.0.0(Jan 12, 2019)

    After months of hard work & testing, we (I and @Joannis) are proud to release MongoKitten 5 (the 150th MongoKitten release!).

    MongoKitten 5, together with OpenKitten BSON 6, is a complete rewrite of the MongoKitten project. Because it is based on Swift NIO, it integrates perfectly in modern Swift frameworks.

    Some highlights include:

    • Streamlined collection APIs
    • Even better performance
    • Fully asynchronous through the core
    • Improved Codable support
    • Support for Change Streams
    • Fully redesigned aggregate pipeline builder
    • Better, more flexible cursors
    • Support for SCRAM SHA256 authentication
    • Mature cluster support through SDAM
    • Support for the new MongoDB Wire Protocol

    And a big thank you to you, the community, for helping MongoKitten get where we stand today.

    If you have any thoughts, questions or other feedback about MongoKitten 5, please feel free to raise an issue or contact @Joannis or @Obbut via our Slack.

    Source code(tar.gz)
    Source code(zip)
Owner
Kittenlishiously awesome Swift libraries
null
Native cross-platform MongoDB management tool

About Robo 3T Robo 3T (formerly Robomongo *) is a shell-centric cross-platform MongoDB management tool. Unlike most other MongoDB admin UI tools, Robo

Studio 3T 8.7k Sep 23, 2021
Mac Native Mongodb Client

System Requirements Mac OS X (10.8.x, 10.9.x, 10.10.x), intel 64bit based. Download HERE Or you can compile it yourself using Xcode Build Just build i

Jérôme Lebel 2.5k Sep 12, 2021
Realm is a mobile database: a replacement for Core Data & SQLite

Realm is a mobile database that runs directly inside phones, tablets or wearables. This repository holds the source code for the iOS, macOS, tvOS & wa

Realm 14.6k Sep 16, 2021
A toolkit for SQLite databases, with a focus on application development

A toolkit for SQLite databases, with a focus on application development Latest release: August 22, 2021 • version 5.10.0 • CHANGELOG • Migrating From

Gwendal Roué 4.2k Sep 20, 2021
Free universal database tool and SQL client

DBeaver Free multi-platform database tool for developers, SQL programmers, database administrators and analysts. Supports any database which has JDBC

DBeaver 22.2k Sep 16, 2021
The easiest way to get started with Redis on the Mac

Redis.app The easiest way to get started with Redis on the Mac Just download, drag to the applications folder, and double-click. Download -- Version n

José Padilla 322 Sep 12, 2021
Unrealm is an extension on RealmCocoa, which enables Swift native types to be saved in Realm.

Unrealm enables you to easily store Swift native Classes, Structs and Enums into Realm . Stop inheriting from Object! Go for Protocol-Oriented program

Artur  Mkrtchyan 459 Sep 14, 2021
A type-safe, Swift-language layer over SQLite3.

SQLite.swift A type-safe, Swift-language layer over SQLite3. SQLite.swift provides compile-time confidence in SQL statement syntax and intent. Feature

Stephen Celis 7.8k Sep 16, 2021
A Cocoa / Objective-C wrapper around SQLite

FMDB v2.7 This is an Objective-C wrapper around SQLite. The FMDB Mailing List: https://groups.google.com/group/fmdb Read the SQLite FAQ: https://www.s

August 13.6k Sep 21, 2021
The easiest way to get started with PostgreSQL on the Mac

Postgres.app The easiest way to run PostgreSQL on your Mac Includes everything you need to get started with PostgreSQL Comes with a pretty GUI to star

Postgres.app 6k Sep 23, 2021
:wrench: Cross-platform GUI management tool for Redis

RDM Install & Run | Quick Start | Native Formatters | Development Guide | Known issues | Telegram Chat Open source cross-platform Desktop Manager for

Igor Malinovskiy 19k Sep 24, 2021
CoreData/Realm sweet wrapper written in Swift

What is SugarRecord? SugarRecord is a persistence wrapper designed to make working with persistence solutions like CoreData in a much easier way. Than

Modo 2.1k Aug 18, 2021
YapDB is a collection/key/value store with a plugin architecture. It's built atop sqlite, for Swift & objective-c developers.

YapDatabase is a collection/key/value store and so much more. It's built atop sqlite, for Swift & Objective-C developers, targeting macOS, iOS, tvOS &

Yap Studios 3.3k Sep 14, 2021
WCDB is a cross-platform database framework developed by WeChat.

WCDB 中文版本请参看这里 WCDB is an efficient, complete, easy-to-use mobile database framework used in the WeChat application. It's currently available on iOS,

Tencent 9.2k Sep 16, 2021
Open source PostgreSQL GUI client for macOS, Linux and Windows

Postbird Postbird is a cross-platform PostgreSQL GUI client, written in JavaScript, runs with Electron Download Version 0.8.4 MacOS: Postbird-0.8.4.dm

Pavel Evstigneev 1.2k Sep 21, 2021
MySQL/MariaDB database management for macOS

Sequel Pro Sequel Pro is a fast, easy-to-use Mac database management application for working with MySQL & MariaDB databases. You can find more details

Sequel Pro 8.5k Sep 19, 2021
Sync Realm Database with CloudKit

IceCream helps you sync Realm Database with CloudKit. It works like magic! Features Realm Database Off-line First Thread Safety Reactive Programming O

Soledad 1.6k Sep 18, 2021
A library that provides the ability to import/export Realm files from a variety of data container formats.

Realm Converter Realm Converter is an open source software utility framework to make it easier to get data both in and out of Realm. It has been built

Realm 204 Jul 28, 2021