不知道有没有人记得 DAY1 文章说本篇使用 .NET 平台,结果一直到第 29 天都还没有写到任何有关的东西,其实原本是想全程使用 .NET 来举例,但考量到观看者不一定使用 C#,还是乖乖回头用 javascript 来说明。
会写这一篇呢是想帮助过去的我自己,当时使用的语言是 C#,因专案要接触 MongoDB,在语法上着实恼了一阵子,明明是很简单的东西却不习惯使用 Mongo C# Driver,导致额外花了不少时间在熟悉工具,要是有这一篇的话,肯定能快速上手(卖瓜?)
本篇文章会像是 Cheat sheet 性质,直接给予语法,一个速食的概念,实际应用在专案上,可以再重构得更漂亮些。另外本篇使用的语法都是强型别为主,毕竟使用 C# 就要发挥它的特性,如果使用字串代替栏位,虽然开发期很轻松快速,但很容易因为 typo 导致要抓 bug 抓很久,别问我为什麽知道,因为开发初期就吃了很多苦XD
以下的范例我们会使用下面这个 entity 来当作举例
[BsonIgnoreExtraElements]
public class SampleClassEntity
{
[BsonId]
public string Id { get; set;}
public int IntField { get; set;}
public string StringField { get; set;}
}
[BsonIgnoreExtraElements]
是忽略没有 mapping 到 c# 端的栏位
[BsonId]
是 Mongo C# driver 的 attribute,代表这个 property 是对应到 MongoDB _id
栏位。
const string MongoAddress = "mongodb://localhost:27017";
const string HelloDatabase = "hellomongodb";
const string Collection = "sample";
var client = new MongoClient(MongoAddress);
public IMongoCollection<SampleClassEntity> GetCollection()
{
var _client = new MongoClient(MongoAddress);
return _client.GetDatabase(HelloDatabase).GetCollection<SampleClassEntity>(Collection);
}
await MongoHelper.GetCollection().InsertOneAsync(new SampleClassEntity());
一次建立多笔(bulk write)会在 Update 那边一起使用,即 MongoDB 的 upsert
var builder = Builders<SampleClassEntity>.Filter;
var dbFilter = builder.Gt(x => x.IntField, 1)
& builder.Eq(x => x.StringField, "ComparedString");
首先我们建立一个 Filter 类型的 builder,接着拼凑出我们要的查询条件。
以上面的范例是 IntField > 1
且 StringField == ComparedString
var someCondition = true;
if (someCondition)
dbFilter &= builder.Gt(x => x.IntField, 2);
也会有一些状况是特定条件下才会有的,上面是如果 someCondition == true
,那就会需要多家这个过滤条件。
var result = await MongoHelper.GetCollection().Find(dbFilter).ToListAsync();
接着我们就可以将此 filter 放入 Find()
内当参数使用。
这边的 await 与 ToListAsync 是非同步用法,如果是同步的呼叫那就不需要加上去。
// Find by cursor
var proj = Builders<SampleClassEntity>.Projection
.Include(x => x.Id)
.Include(x => x.IntField);
using var cursor = await MongoHelper.GetCollection()
.WithReadPreference(ReadPreference.SecondaryPreferred)
.FindAsync(dbFilter, new FindOptions<SampleClassEntity>
{
Sort = Builders<SampleClassEntity>.Sort.Descending(x => x.Id),
Skip = 1,
Limit = 2,
Projection = proj
});
var result = cursor.ToEnumerable().ToArray();
这边除了使用 cursor 方式之外多了一些东西。
Projection
Include
与 Exclude
WithReadPreference(ReadPreference.SecondaryPreferred)
ReadPreference
enum 定义了那些FindOptions
更新分为 Upsert 与 Replace 两个项目来讲,但本质上不会差太多的,一个是更新(设定)特定栏位,另一个是整个物件取代。
这边的范例是直接用 BulkWrite 方式,批量进行修改了。
var src = Array.Empty<SampleClassEntity>();
var bulks = src.Select(entity =>
{
return new UpdateOneModel<SampleClassEntity>
(
Builders<SampleClassEntity>.Filter.Eq(x => x.Id, ""),
Builders<SampleClassEntity>.Update
.Inc(x => x.IntField, 1)
.Set(x => x.StringField, "2")
) {IsUpsert = true};
}).ToArray();
await MongoHelper.GetCollection().BulkWriteAsync(bulks, new BulkWriteOptions{IsOrdered = false});
Update 的方式须特别指定要更新的栏位,这边举了
Inc
即 Increment,增加数量的意思
Set
更新成新值
SetOnInsert
是在第一次写入时才会使用该值,後面任何 Update 都不会修改
IsOrdered
整批量个更新不需要按顺序执行(之前文章有提到)
var src = Array.Empty<SampleClassEntity>();
var bulks = src.Select(x =>
{
var replace = new ReplaceOneModel<SampleClassEntity>(
Builders<SampleClassEntity>.Filter.Eq(m => m.Id, x.Id), x)
{IsUpsert = true};
return replace;
}).ToArray();
await MongoHelper.GetCollection().BulkWriteAsync(bulks);
Replace 相对单纯一些,只需要 Filter 找到特定的文件,进行整个内容取代。
var filter = Builders<SampleClassEntity>.Filter.In(x => x.Id, new[] {"ToDeleteId"});
await MongoHelper.GetCollection().DeleteManyAsync(filter);
删除部分是直接用 DeleteMany
,可以按需求使用 DeleteOne
。
最後还是要强调,这只是语法的演示,实务上需要再调整写法与效能。
本系列文章会同步发表於我个人的部落格 Pie Note
>>: Day 14 淘家集运流程设计分享 (今天休一天,分享最近接的案)
Iteration for (var i=0; i<myArr.length; i++){}...
单一按钮样式元件 前篇有写到单一按钮,可以把样式拆成元件来使用。如下: @layer compon...
历史重要性 CNN历史已发生,为何要花时间了解它?个人认为了解CNN历史可以让我们选择以同方式解决不...
今天的内容是该如何简单地做到第三人称视角 ...
前言 把手边的工具都了解一遍,像是合约、订阅等等。尤其是昨天的订阅,让我们更前一步,但是实际上这样的...