MongoDB 4.4.4 change stream returns 更新所有文件而不是过滤条件匹配一个?
MongoDB 4.4.4 change stream returns all document updates rather than filtered condition matched one?
我正在寻找集合中单个文档的 'update' 操作的通知,据推测当该特定文档更新时 MongoDB 会通知 'watch' 注册的 .net 客户端,但是实际情况是 MongoDB returns 集合中所有具有 'update' 操作的文档,无论过滤器集的“匹配”条件如何。
任何有 Change Stream 经验的人都可以帮忙吗?是MongoDB换流的nature/design吗?
下面是.net C#客户端的测试代码,
class:
public class UserInfo
{
[BsonId, BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
[BsonElement("UserName", Order = 1), BsonRepresentation(BsonType.String)]
public string UserName { get; set; }
[BsonElement("Password", Order = 2), BsonRepresentation(BsonType.String)]
public string Password { get; set; }
[BsonElement("LastName", Order = 3), BsonRepresentation(BsonType.String)]
public string LastName { get; set; }
[BsonElement("FirstName", Order = 4), BsonRepresentation(BsonType.String)]
public string FirstName { get; set; }
[BsonElement("Email", Order = 5), BsonRepresentation(BsonType.String)]
public string Email { get; set; }
}
过滤条件管道:
collection = myDB.GetCollection<UserInfo>("Users");
var options = new ChangeStreamOptions
{
FullDocument = ChangeStreamFullDocumentOption.UpdateLookup,
};
var pipeline = new EmptyPipelineDefinition<ChangeStreamDocument<UserInfo>>();
pipeline.Match(g => g.OperationType == ChangeStreamOperationType.Update)
.Match(o => o.FullDocument.UserName.Contains("Alice"))
.Match(t => t.UpdateDescription.UpdatedFields.ToString().Contains(nameof(UserInfo.Password)));
Task watchTask = WatchCollection();
更改事件处理例程:
private static async Task WatchCollection()
{
var cursor = await collection.WatchAsync(pipeline, options);
Debug.WriteLine("ChangeStream started.");
await cursor.ForEachAsync(change =>
{
Debug.WriteLine("Matched UserName: " + change.FullDocument.UserName);
});
}
从上面的例程来看,更改事件不会根据过滤条件进行工作,每次触发此例程时,'change.FullDocument.UserName' 实际上会打印出集合中获得 'update' 操作的每个文档,这很奇怪。
我能够让它与以下内容一起工作:
var options = new ChangeStreamOptions
{
FullDocument = ChangeStreamFullDocumentOption.UpdateLookup,
BatchSize = 1
};
var filter = Builders<ChangeStreamDocument<UserInfo>>
.Filter.Where(x =>
x.OperationType == ChangeStreamOperationType.Update &&
x.FullDocument.UserName.Contains("Alice"));
filter &= Builders<ChangeStreamDocument<UserInfo>>.Filter.Exists("updateDescription.updatedFields.Password");
var pipeline = new IPipelineStageDefinition[]
{
PipelineStageDefinitionBuilder.Match(filter)
};
using (var cursor = await collection.WatchAsync<ChangeStreamDocument<UserInfo>>(pipeline, options))
{
while (await cursor.MoveNextAsync())
{
foreach (var info in cursor.Current)
{
Console.WriteLine("Updated: " + info.FullDocument.UserName);
}
}
}
如果你不介意使用图书馆,上面所有的歌舞都可以避免,事情可以提炼如下:
var watcher = DB.Watcher<UserInfo>("on-alice-updates-password");
watcher.Start(
eventTypes: EventType.Updated,
filter: b => b.Where(x => x.FullDocument.UserName == "Alice") &
b.Exists("updateDescription.updatedFields.Password"));
watcher.OnChanges += docs =>
{
foreach (var doc in docs)
Console.WriteLine("Updated: " + doc.UserName);
};
查看 MongoDB.Entities 文档了解更多信息。免责声明:我是该库的作者。
我正在寻找集合中单个文档的 'update' 操作的通知,据推测当该特定文档更新时 MongoDB 会通知 'watch' 注册的 .net 客户端,但是实际情况是 MongoDB returns 集合中所有具有 'update' 操作的文档,无论过滤器集的“匹配”条件如何。
任何有 Change Stream 经验的人都可以帮忙吗?是MongoDB换流的nature/design吗?
下面是.net C#客户端的测试代码,
class:
public class UserInfo
{
[BsonId, BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
[BsonElement("UserName", Order = 1), BsonRepresentation(BsonType.String)]
public string UserName { get; set; }
[BsonElement("Password", Order = 2), BsonRepresentation(BsonType.String)]
public string Password { get; set; }
[BsonElement("LastName", Order = 3), BsonRepresentation(BsonType.String)]
public string LastName { get; set; }
[BsonElement("FirstName", Order = 4), BsonRepresentation(BsonType.String)]
public string FirstName { get; set; }
[BsonElement("Email", Order = 5), BsonRepresentation(BsonType.String)]
public string Email { get; set; }
}
过滤条件管道:
collection = myDB.GetCollection<UserInfo>("Users");
var options = new ChangeStreamOptions
{
FullDocument = ChangeStreamFullDocumentOption.UpdateLookup,
};
var pipeline = new EmptyPipelineDefinition<ChangeStreamDocument<UserInfo>>();
pipeline.Match(g => g.OperationType == ChangeStreamOperationType.Update)
.Match(o => o.FullDocument.UserName.Contains("Alice"))
.Match(t => t.UpdateDescription.UpdatedFields.ToString().Contains(nameof(UserInfo.Password)));
Task watchTask = WatchCollection();
更改事件处理例程:
private static async Task WatchCollection()
{
var cursor = await collection.WatchAsync(pipeline, options);
Debug.WriteLine("ChangeStream started.");
await cursor.ForEachAsync(change =>
{
Debug.WriteLine("Matched UserName: " + change.FullDocument.UserName);
});
}
从上面的例程来看,更改事件不会根据过滤条件进行工作,每次触发此例程时,'change.FullDocument.UserName' 实际上会打印出集合中获得 'update' 操作的每个文档,这很奇怪。
我能够让它与以下内容一起工作:
var options = new ChangeStreamOptions
{
FullDocument = ChangeStreamFullDocumentOption.UpdateLookup,
BatchSize = 1
};
var filter = Builders<ChangeStreamDocument<UserInfo>>
.Filter.Where(x =>
x.OperationType == ChangeStreamOperationType.Update &&
x.FullDocument.UserName.Contains("Alice"));
filter &= Builders<ChangeStreamDocument<UserInfo>>.Filter.Exists("updateDescription.updatedFields.Password");
var pipeline = new IPipelineStageDefinition[]
{
PipelineStageDefinitionBuilder.Match(filter)
};
using (var cursor = await collection.WatchAsync<ChangeStreamDocument<UserInfo>>(pipeline, options))
{
while (await cursor.MoveNextAsync())
{
foreach (var info in cursor.Current)
{
Console.WriteLine("Updated: " + info.FullDocument.UserName);
}
}
}
如果你不介意使用图书馆,上面所有的歌舞都可以避免,事情可以提炼如下:
var watcher = DB.Watcher<UserInfo>("on-alice-updates-password");
watcher.Start(
eventTypes: EventType.Updated,
filter: b => b.Where(x => x.FullDocument.UserName == "Alice") &
b.Exists("updateDescription.updatedFields.Password"));
watcher.OnChanges += docs =>
{
foreach (var doc in docs)
Console.WriteLine("Updated: " + doc.UserName);
};
查看 MongoDB.Entities 文档了解更多信息。免责声明:我是该库的作者。