MongoKitten 5.1.11

MongoKitten 5.1.11

Joannis OrlandosRobbert Brandsma 维护。



OpenKitten

OpenKitten

安装 | 基本使用 | 关于 BSON | Codable | 社区 | 如何帮助

一个快速的、纯 Swift MongoDB 驱动,基于 Swift NIO 构建,适用于服务器端 Swift。它具有出色的 API 和经过战斗考验的核心,支持服务器和嵌入式环境中的 MongoDB。

⭐️请留下一个星标来支持 MongoKitten – 它真的很有帮助!

🕶安装

设置 MongoDB 服务器

如果您还没有设置 MongoDB 服务器,您应该设置一个 MongoDB 服务器来开始使用 MongoKitten

对于开发,这可以在您的本地机器上进行。

UbuntumacOS任何其他支持的 Linux 发行版 安装 MongoDB。

或者,使用数据库即服务(DAAS)如 MongoDB AtlasMLabIBM Cloud 或其他许多服务。

如果您旨在使用 MongoKitten 移动版,请向下滚动!

将 MongoKitten 添加到您的 Swift 项目中🚀

MongoKitten 支持 Swift 包管理器,用于服务器端应用程序。将 MongoKitten 添加到您的 Package.swift 文件中的依赖项

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

另外,别忘了将 "MongoKitten" 作为依赖项添加到您的目标中。

移动功能 [Beta]

MongoKitten 现在也支持嵌入式 MongoDB 数据库(测试版)。

对于 MongoKitten 移动版本,我们依赖于 Cocoapods。目前尚不支持使用 MongoKitten,但您可以通过将以下内容添加到您的 Podfile 中开始使用。

pod 'MongoKitten'

🚲基本用法

连接到您的数据库

import MongoKitten

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

Vapor 用户应将数据库注册为服务。

let connectionURI = "mongodb://"

services.register { container -> MongoKitten.Database in
    return try MongoKitten.Database.lazyConnect(connectionURI, on: container.eventLoop)
}

对于嵌入式数据库

// WARNING: Force unwrap will crash your application on failure
let mongo = try! MobileDatabase(settings: .default())

URI注意事项

MongoKitten 尚不支持 MongoDB v3.6 连接 URIs。您需要使用旧的连接 URI 格式。

如果您不确定;以 mongodb+srv:// 开头的连接字符串是 3.6 连接 URI,而以 mongodb:// 开头的 URIs 是旧格式。

NIO Futures

MongoKitten 依赖于 [Swift NIO](https://github.com/apple/swift-nio) 来提供对异步操作的支持。所有与服务器通信的 MongoKitten 操作都是异步的,并返回某种类型的 EventLoopFuture。

您可以通过阅读 其自述文件 或阅读 RayWenderlich.com 上的文章 来了解所有关于 NIO 的信息,但以下是基础知识

异步操作返回一个未来。NIO 在 EventLoopFuture<T> 类型中实现未来。一个 EventLoopFuture 是一个将来会提供结果的持有者。未来的结果可以是成功的,返回类型为 T,或者失败的,返回类型为 Swift 的 Error。这是异步表示成功 return 或抛出的错误。

如果您正在使用 Vapor,请参阅他们的 异步文档。Vapor的异步模块在NIO之上提供了额外的助手,使得使用 EventLoopFuture<T> 的实例变得更加容易。

如果您使用Vapor或其他基于Swift-NIO的Web框架,绝对不要EventLoopFuture 实例上使用 wait() 函数。

CRUD(创建、读取、更新、删除)

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

创建(插入)

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

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

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

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

读取(查找)和查询构建器

要在MongoDB中执行以下查询

{
	"username": "kitty"
}

使用以下MongoKitten代码

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

要在MongoDB中执行以下查询

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

使用以下MongoKitten代码

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

您也可以自己输入查询,而不使用查询构建器,如下所示

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

游标

查找操作返回一个 Cursor。游标是查询结果集的指针。您可以通过遍历结果或获取一个或所有结果来从游标获取结果。

获取结果

您可以获取所有结果作为数组

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

请注意,这可能在结果集非常大时很危险。只有当您确定查询的整个结果集可以舒适地放入内存时,才使用 getAllResults()

遍历结果

为了更有效地处理结果,您可以懒加载地遍历一个光标

let doneIterating: EventLoopFuture<Void> = users.find().forEach { user: Document in
	// ...
}
光标是泛型的

查找操作返回一个 FindCursor。如您所见,FindCursor 是一个泛型类型。您可以使用 map 函数懒加式地将光标转换成不同的结果类型,这与数组或文档上的 map 操作类似

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

更新

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

删除

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

📦关于 BSON 和文档

MongoDB 是一个文档数据库,底层使用 BSON 存储类似 JSON 的数据。MongoKitten 通过其配套项目 BSON 规范 实现 OpenKitten/BSON。您可以在单独的 BSON 仓库中找到更多关于我们的 BSON 实现信息,但这里有一些基本内容

文本字面量

您通常会像这样创建 BSON 文档:

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

从上面的例子中,我们可以了解以下几点:

  • BSON 文档可以表示数组或字典
  • 您可以使用字面量初始化文档,就像初始化常规字典和数组一样
  • 文档中的值(无论是数组元素还是字典对的值)可以是任何 BSON 原始类型
  • BSON 原始类型包括 Swift 的核心类型,如 IntStringDoubleBool,以及来自 Foundation 的 Date
  • BSON 还包含一些独特类型,如 ObjectId

又一个集合

与普通数组和字典一样,`Document`遵循`Collection`协议。因此,您可以直接使用`Document`,并使用您已经从`Array`和`Dictionary`知道的API进行操作。例如,您可以使用for循环遍历文档。

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

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

文档还提供了下标来访问单个元素。下标返回`Primitive?`类型的值,因此在使用之前您可能需要使用`as?`进行类型转换。

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

在将`Document`和`Dictionary`之间转换之前请三思

我们的`Document`类型实现了优化、高效的方式,并提供了许多读取和操作数据的实用功能,包括Swift `Dictionary`类型上没有的功能。除此之外,`Document`还实现了大多数`Dictionary`上的API,因此学习曲线非常平缓。

💾可编码

MongoKitten通过提供`BSONEncoder`和`BSONDecoder`类型支持`Encodable`和`Decodable`(可编码)协议。使用我们的编码和解码器与使用Foundation `JSONEncoder`和`JSONDecoder`类的工作非常相似,区别在于`BSONEncoder`生产`Document`实例,而`BSONDecoder`接受`Document`实例,而不是`Data`。

例如,假设我们想编码以下结构体

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
	}
}

我们可以这样编码和解码实例

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)

一些说明

  • `BSONEncoder`和`BSONDecoder`与其它编码和解码器工作方式非常相似
  • 嵌套类型也可以编码,也是推荐的
    • 嵌套结构体和类通常编码为嵌入文档
  • 您可以使用编码/解码策略自定义表示形式

可编码和游标

在对`find`查询进行操作时,可以懒加载`Cursor`的结果。懒加载映射比将整个结果集保持在内存中更为高效,因为它允许有效地使用`forEach-`循环,从而降低应用程序的内存压力。您还可以使用可编码功能利用游标。

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

🐱社区

在这里加入我们的Slack,成为欢迎的社区的一部分

✌️如何帮助

支持 MongoKitten 发展

在这里接受项目捐赠。我们希望能够建立一个良好的测试环境以及大量的文档、教程和示例。

为 MongoKitten 作出贡献

  • 有关贡献的信息,请参阅 CONTRIBUTING.md
  • 您可以通过解决 TODOs 和回复问题来帮助我们
  • 当然,任何正面或负面的反馈都有助于改进项目

☠️许可协议

MongoKitten 采用 MIT 许可协议。