C# MongoDb : 在字段上插入匹配
C# MongoDb : Upsert matching on a field
所以我有一个对象列表,有些会存在于 Mongo 中,有些则不会。
- 对于已存在的,我要更新 1 个字段
- 对于不存在的对象,请插入整页对象。
我想通过他们的 url 找到他们。有办法吗?
var webapges = new List<WriteModel<Page>>();
var filterDefinition = Builders<Page>.Filter.Eq(p => p.url, **Object.url**);
var updateDefinition = Builders<Page>.Update.Set(p => p.pop, p.pop + **Object.pop??**);
listWrites.Add(new UpdateOneModel<Page>(filterDefinition, updateDefinition));
await userCollection.BulkWriteAsync(listWrites);
public class Page
{
[BsonId] public ObjectId Id { get; set; }
[BsonElement("url")] public string Url { get; set; }
[BsonElement("level")] public int Level { get; set; }
[BsonElement("languages")] public string Languages { get; set; }
[BsonElement("proc")] public int Proc { get; set; }
[BsonElement("domain")] public string Domain { get; set; }
[BsonElement("len")] public int Len { get; set; }
[BsonElement("html")] public string Html { get; set; }
[BsonElement("body")] public string Body { get; set; }
[BsonElement("title")] public string Title { get; set; }
[BsonElement("meta")] public string Meta { get; set; }
[BsonElement("scan_date")] public BsonDateTime ScanDate { get; set; }
[BsonElement("pop")] public int Popularity { get; set; }
}
正如 Joe 在评论中所说,您可以将每次更新设为 Upset,这是 UpdateOneModel<T>
上的 属性,然后您必须设置每个 属性 您想要的使用 $setOnInsert 更新运算符在插入上设置。
因此,让我们开始使用一些数据来设置一个新的数据库:
var client = new MongoClient();
var database = client.GetDatabase("test");
await client.DropDatabaseAsync(database.DatabaseNamespace.DatabaseName);
var collection = database.GetCollection<Page>("collection1");
// Create our mix of pages
var pages = new List<Page>
{
new Page {Url = "https://some-url/1", Body = "body1", Popularity = 0, ScanDate = DateTime.UtcNow},
new Page {Url = "https://some-url/2", Body = "body1", Popularity = 0, ScanDate = DateTime.UtcNow},
new Page {Url = "https://some-url/3", Body = "body1", Popularity = 0, ScanDate = DateTime.UtcNow}
};
// Insert the middle one.
await collection.InsertOneAsync(pages[1]);
Debugger.Break();
现在,如果我们进入 shell 并查看到目前为止的数据,我们将在集合中有一页要更新。
> use test
switched to db test
> show collections
collection1
> db.collection1.find().pretty()
{
"_id" : ObjectId("5e80824b0664ae4020ee68b3"),
"url" : "https://some-url/2",
"level" : 0,
"languages" : null,
"proc" : 0,
"domain" : null,
"len" : 0,
"html" : null,
"body" : "body1",
"title" : null,
"meta" : null,
"scan_date" : ISODate("2020-03-29T11:11:07.700Z"),
"pop" : 0
}
现在让我们将页面上的所有流行度属性更新为 100 以查看变化。
// Update all popularity to 100
pages.ForEach(x => x.Popularity = 100);
然后我们可以使用一些 LINQ 来创建我们将发送到批写入的更新模型。
// Create all the updates as a batch
var updateOneModels = pages.Select(x =>
{
var filterDefinition = Builders<Page>.Filter.Eq(p => p.Url, x.Url);
var updateDefinition = Builders<Page>.Update.Set(p => p.Popularity, x.Popularity)
.SetOnInsert(p => p.Level, x.Level)
.SetOnInsert(p => p.Languages, x.Languages)
.SetOnInsert(p => p.Proc, x.Proc)
.SetOnInsert(p => p.Domain, x.Domain)
.SetOnInsert(p => p.Len, x.Len)
.SetOnInsert(p => p.Html, x.Html)
.SetOnInsert(p => p.Body, x.Body)
.SetOnInsert(p => p.Title, x.Title)
.SetOnInsert(p => p.Meta, x.Meta)
.SetOnInsert(p => p.ScanDate, x.ScanDate);
return new UpdateOneModel<Page>(filterDefinition, updateDefinition) { IsUpsert = true };
}).ToList();
现运行批量
// Run the batch
await collection.BulkWriteAsync(updateOneModels);
现在,如果我们查看 shell 中的数据,我们的中间页面现已更新,其他所有内容均已插入
> db.collection1.find().pretty()
{
"_id" : ObjectId("5e80824b0664ae4020ee68b3"),
"url" : "https://some-url/2",
"level" : 0,
"languages" : null,
"proc" : 0,
"domain" : null,
"len" : 0,
"html" : null,
"body" : "body1",
"title" : null,
"meta" : null,
"scan_date" : ISODate("2020-03-29T11:11:07.700Z"),
"pop" : 100
}
{
"_id" : ObjectId("5e80825cc38a0ff23e1eb326"),
"url" : "https://some-url/1",
"body" : "body1",
"domain" : null,
"html" : null,
"languages" : null,
"len" : 0,
"level" : 0,
"meta" : null,
"pop" : 100,
"proc" : 0,
"scan_date" : ISODate("2020-03-29T11:11:07.699Z"),
"title" : null
}
{
"_id" : ObjectId("5e80825cc38a0ff23e1eb327"),
"url" : "https://some-url/3",
"body" : "body1",
"domain" : null,
"html" : null,
"languages" : null,
"len" : 0,
"level" : 0,
"meta" : null,
"pop" : 100,
"proc" : 0,
"scan_date" : ISODate("2020-03-29T11:11:07.700Z"),
"title" : null
}
所以我有一个对象列表,有些会存在于 Mongo 中,有些则不会。
- 对于已存在的,我要更新 1 个字段
- 对于不存在的对象,请插入整页对象。
我想通过他们的 url 找到他们。有办法吗?
var webapges = new List<WriteModel<Page>>();
var filterDefinition = Builders<Page>.Filter.Eq(p => p.url, **Object.url**);
var updateDefinition = Builders<Page>.Update.Set(p => p.pop, p.pop + **Object.pop??**);
listWrites.Add(new UpdateOneModel<Page>(filterDefinition, updateDefinition));
await userCollection.BulkWriteAsync(listWrites);
public class Page
{
[BsonId] public ObjectId Id { get; set; }
[BsonElement("url")] public string Url { get; set; }
[BsonElement("level")] public int Level { get; set; }
[BsonElement("languages")] public string Languages { get; set; }
[BsonElement("proc")] public int Proc { get; set; }
[BsonElement("domain")] public string Domain { get; set; }
[BsonElement("len")] public int Len { get; set; }
[BsonElement("html")] public string Html { get; set; }
[BsonElement("body")] public string Body { get; set; }
[BsonElement("title")] public string Title { get; set; }
[BsonElement("meta")] public string Meta { get; set; }
[BsonElement("scan_date")] public BsonDateTime ScanDate { get; set; }
[BsonElement("pop")] public int Popularity { get; set; }
}
正如 Joe 在评论中所说,您可以将每次更新设为 Upset,这是 UpdateOneModel<T>
上的 属性,然后您必须设置每个 属性 您想要的使用 $setOnInsert 更新运算符在插入上设置。
因此,让我们开始使用一些数据来设置一个新的数据库:
var client = new MongoClient();
var database = client.GetDatabase("test");
await client.DropDatabaseAsync(database.DatabaseNamespace.DatabaseName);
var collection = database.GetCollection<Page>("collection1");
// Create our mix of pages
var pages = new List<Page>
{
new Page {Url = "https://some-url/1", Body = "body1", Popularity = 0, ScanDate = DateTime.UtcNow},
new Page {Url = "https://some-url/2", Body = "body1", Popularity = 0, ScanDate = DateTime.UtcNow},
new Page {Url = "https://some-url/3", Body = "body1", Popularity = 0, ScanDate = DateTime.UtcNow}
};
// Insert the middle one.
await collection.InsertOneAsync(pages[1]);
Debugger.Break();
现在,如果我们进入 shell 并查看到目前为止的数据,我们将在集合中有一页要更新。
> use test
switched to db test
> show collections
collection1
> db.collection1.find().pretty()
{
"_id" : ObjectId("5e80824b0664ae4020ee68b3"),
"url" : "https://some-url/2",
"level" : 0,
"languages" : null,
"proc" : 0,
"domain" : null,
"len" : 0,
"html" : null,
"body" : "body1",
"title" : null,
"meta" : null,
"scan_date" : ISODate("2020-03-29T11:11:07.700Z"),
"pop" : 0
}
现在让我们将页面上的所有流行度属性更新为 100 以查看变化。
// Update all popularity to 100
pages.ForEach(x => x.Popularity = 100);
然后我们可以使用一些 LINQ 来创建我们将发送到批写入的更新模型。
// Create all the updates as a batch
var updateOneModels = pages.Select(x =>
{
var filterDefinition = Builders<Page>.Filter.Eq(p => p.Url, x.Url);
var updateDefinition = Builders<Page>.Update.Set(p => p.Popularity, x.Popularity)
.SetOnInsert(p => p.Level, x.Level)
.SetOnInsert(p => p.Languages, x.Languages)
.SetOnInsert(p => p.Proc, x.Proc)
.SetOnInsert(p => p.Domain, x.Domain)
.SetOnInsert(p => p.Len, x.Len)
.SetOnInsert(p => p.Html, x.Html)
.SetOnInsert(p => p.Body, x.Body)
.SetOnInsert(p => p.Title, x.Title)
.SetOnInsert(p => p.Meta, x.Meta)
.SetOnInsert(p => p.ScanDate, x.ScanDate);
return new UpdateOneModel<Page>(filterDefinition, updateDefinition) { IsUpsert = true };
}).ToList();
现运行批量
// Run the batch
await collection.BulkWriteAsync(updateOneModels);
现在,如果我们查看 shell 中的数据,我们的中间页面现已更新,其他所有内容均已插入
> db.collection1.find().pretty()
{
"_id" : ObjectId("5e80824b0664ae4020ee68b3"),
"url" : "https://some-url/2",
"level" : 0,
"languages" : null,
"proc" : 0,
"domain" : null,
"len" : 0,
"html" : null,
"body" : "body1",
"title" : null,
"meta" : null,
"scan_date" : ISODate("2020-03-29T11:11:07.700Z"),
"pop" : 100
}
{
"_id" : ObjectId("5e80825cc38a0ff23e1eb326"),
"url" : "https://some-url/1",
"body" : "body1",
"domain" : null,
"html" : null,
"languages" : null,
"len" : 0,
"level" : 0,
"meta" : null,
"pop" : 100,
"proc" : 0,
"scan_date" : ISODate("2020-03-29T11:11:07.699Z"),
"title" : null
}
{
"_id" : ObjectId("5e80825cc38a0ff23e1eb327"),
"url" : "https://some-url/3",
"body" : "body1",
"domain" : null,
"html" : null,
"languages" : null,
"len" : 0,
"level" : 0,
"meta" : null,
"pop" : 100,
"proc" : 0,
"scan_date" : ISODate("2020-03-29T11:11:07.700Z"),
"title" : null
}