MongoKitten alternatives and similar libraries
Based on the "Database" category.
Alternatively, view MongoKitten alternatives based on common mentions on social networks and blogs.
-
MMKV
An efficient, small mobile key-value storage framework developed by WeChat. Works on Android, iOS, macOS, Windows, and POSIX. -
YapDatabase
YapDB is a collection/key/value store with a plugin architecture. It's built atop sqlite, for Swift & objective-c developers. -
ParseAlternatives
DISCONTINUED. GraphQLite is a toolkit to work with GraphQL servers easily. It also provides several other features to make life easier during iOS application development. [Moved to: https://github.com/relatedcode/GraphQLite] -
Unrealm
Unrealm is an extension on RealmCocoa, which enables Swift native types to be saved in Realm. -
Prephirences
Prephirences is a Swift library that provides useful protocols and convenience methods to manage application preferences, configurations and app-state. UserDefaults -
PredicateEditor
A GUI for dynamically creating NSPredicates at runtime to query data in your iOS app. -
realm-cocoa-converter
A library that provides the ability to import/export Realm files from a variety of data container formats. -
SecureDefaults
Elevate the security of your UserDefaults with this lightweight wrapper that adds a layer of AES-256 encryption -
MySQL
A stand-alone Swift wrapper around the MySQL client library, enabling access to MySQL servers. -
PersistenceKit
Store and retrieve Codable objects to various persistence layers, in a couple lines of code! -
PersistentStorageSerializable
Swift library that makes easier to serialize the user's preferences (app's settings) with system User Defaults or Property List file on disk. -
ObjectiveRocks
An Objective-C wrapper for RocksDB - A Persistent Key-Value Store for Flash and RAM Storage. -
PostgreSQL
A stand-alone Swift wrapper around the libpq client library, enabling access to PostgreSQL servers. -
MongoDB
A stand-alone Swift wrapper around the mongo-c client library, enabling access to MongoDB servers. -
FileMaker
A stand-alone Swift wrapper around the FileMaker XML Web publishing interface, enabling access to FileMaker servers.
InfluxDB - Purpose built for real-time analytics at any scale.
* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of MongoKitten or a related project?
README
[OpenKitten](assets/ReadmeHeader.svg)
[OpenKitten](assets/Descriptions.gif)
[Installation](#-installation) | Tutorial | [Basic usage](#-basic-usage) | [About BSON](#-about-bson--documents) | [Codable](#-codable) | [Community](#-community) | [How to help](#-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](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 ๐
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/orlandos-nl/MongoKitten.git", from: "7.0.0")
Also, don't forget to add the product "MongoKitten"
as a dependency for your target.
.product(name: "MongoKitten", package: "MongoKitten"),
Add Meow (Optional)
Meow is an ORM that resides in this same package.
.product(name: "Meow", package: "MongoKitten"),
FAQ
I can't connect to MongoDB, authentication fails!
- Make sure you've specified
authSource=admin
, unless you know what your authSource is. MongoDB's default value is really confusing. - 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 await MongoDatabase.connect(to: "mongodb://localhost/my_database")
Vapor users should register the database as a service.
extension Request {
public var mongoDB: MongoDatabase {
return application.mongoDB
}
// 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(to: connectionStringeventLoopGroup)
}
}
And make sure to call app.initializeMongoDB
!
CRUD (Create, Read, Update, Delete)
// The collection "users" in your database
let users = db["users"]
Create (insert)
let myUser: Document = ["username": "kitty", "password": "meow"]
try await users.insert(myUser)
Read (find) and the query builder
To perform the following query in MongoDB:
{
"username": "kitty"
}
Use the following MongoKitten code:
if let kitty = try await users.findOne("username" == "kitty") {
// We've found kitty!
}
To perform the following query in MongoDB:
{
"$or": [
{ "age": { "$lte": 16 } },
{ "age": { "$exists": false } }
]
}
Use the following MongoKitten code:
for try await user in users.find("age" <= 16 || "age" == nil) {
// Asynchronously iterates over each user in the cursor
}
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.
Cursors will close automatically if the enclosing Task
is cancelled
Fetching results
You can fetch all results as an array:
let users = try await users.find().drain()
Note that this is potentially dangerous with very large result sets. Only use drain()
when you are sure that the entire result set of your query fits comfortably in memory.
Cursors are generic
Find operations return a FindQueryBuilder
. You can lazily transform this (and other) cursors into a different result type by using map
, which works similar to map
on arrays or documents. A simple commonly used helper based on map is .decode(..)
which decodes each result Document into a Decodable
entity of your choosing.
let users: [User] = try await users.find().decode(User.self).drain()
Update & Delete
You can do updateOne/many and deleteOne/many the same way you'd see in the MongoDB docs.
try await users.updateMany(where: "username" == "kitty", setting: ["age": 3])
The result is implicitly discarded, but you can still get and use it.
let reply = try await users.deleteOne(where: "username" == "kitty")
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
andBool
, as well asDate
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
andBSONDecoder
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
Meow
Meow works as a lightweight but powerful ORM layer around MongoKitten.
Models
There are two main types of models in Meow, these docs will focus on the most common one.
When creating a model, your type must implement the Model
protocol.
import Meow
struct User: Model {
..
}
Each Model has an _id
field, as required by MongoDB. The type must be Codable and Hashable, the rest is up to you. You can therefore also make _id
a compound key such as a struct
. It must still be unique and hashable, but the resulting Document is acceptable for MongoDB.
Each field must be marked with the @Field
property wrapper:
import Meow
struct User: Model {
@Field var _id: ObjectId
@Field var email: String
}
You can also mark use nested types, as you'd expect of MongoDB. Each field in these nested types must also be makred with @Field
to make it queryable.
import Meow
struct UserProfile: Model {
@Field var firstName: String?
@Field var lastName: String?
@Field var age: Int
}
struct User: Model {
@Field var _id: ObjectId
@Field var email: String
@Field var profile: UserProfile
}
Queries
Using the above model, we can query it from a MeowCollection. Get your instance from the MeowDatabase using a subscritp!
let users = meow[User.self]
Next, run a find
or count
query:
let adultCount = try await users.count(matching: { user in
user.$profile.$age >= 18
})
As meow just recycles common MongoKitten types, you can use a find query cursor as you'd do in MongoKitten.
let kids = try await users.find(matching: { user in
user.$profile.$age < 18
})
for try await kid in kids {
// Send verificatin email to parents
}
References
Meow has a helper type called Reference
, you can use this in your model instead of copying the identifier over. This will give you some extra helpers when trying to resolve a models.
Reference is also Codable
and inherit's the identifier's LosslessStringConvertible
. So it can be used in Vapor's JWT Tokens as a subject, or in a Vapor's Route Parameters.
app.get("users", ":id") { req async throws -> User in
let id: Reference<User> = req.parameters.require("id")
return try await id.resolve(in: req.meow)
}
โ ๏ธ License
MongoKitten is licensed under the MIT license.
*Note that all licence references and agreements mentioned in the MongoKitten README section above
are relevant to that project's source code only.