【发布时间】:2020-05-04 19:16:53
【问题描述】:
我正在尝试使用具有流畅接口的聚合管道但没有成功,但我没有收到任何错误(结果中的所有字段均为空)。
我有这个 User 类:
public class User
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id;
...
[BsonElement("last_access")]
public DateTime LastAccess;
}
实体类:
public class Entity
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id;
...
[BsonElement("active")]
public bool Active;
[BsonElement("user_id")]
public string UserId;
}
UserLookup 类。这用于$lookup。
class UserLookup
{
public int EntityCount;
public IEnumerable<User> UsersData;
}
UserResult 类。这用于分组和投影。
class UserResult
{
public string UserId;
public int EntityCount;
public User UserData;
}
在我的函数中,我有这样的东西:
IMongoCollection<Entity> entityCol = Database.Instance.GetCollection<Entity>("entities");
IMongoCollection<User> usersCol = Database.Instance.GetCollection<User>("users");
IAsyncCursor<UserResult> result = entityCol.Aggregate()
.Match(e => e.Active)
.Group(e => e.UserId, g => new UserResult {
UserId = g.Key,
EntityCount = g.Count()
})
.Lookup<UserResult, User, UserLookup>(usersCol,
lf => lf.UserId, // localField. UserResult.UserId
ff => ff.Id, // foreignField. User.Id
r => r.UsersData // result. UserLookup.UsersData
)
.Project(p => new UserResult {
UserId = p.UserId,
EntityCount = p.EntityCount,
UserData = p.UsersData.First()
})
.ToCursor();
while (result.MoveNext()) {
foreach (var ur in result.Current) {
// ur.UserId = null; ur.UserData = null; ur.EntityCount = 0;
}
}
我没有收到任何错误,但EntityCount 始终为 0,UserId 和 UserData 均为空。基本上,我想要的是:
- 获取所有处于活动状态的实体 (
Match)。 - 按用户 ID (
Group) 对它们进行分组。 - 在用户集合中查找以获取用户数据 (
Lookup)。 - 投影结果以返回一个包含实体计数和用户数据的简单对象 (
Project)。
----- 更新 1
好的,在玩了mongo shell之后,我想我发现了问题。似乎 mongo 无法找到带有ObjectId 的 id 条目,只能使用字符串。这很奇怪,我找到了this answer,似乎可以使用 ObjectId 找到(至少在过去)。
在 mongo shell 中,如果我使用 db.users.find({ _id: ObjectId("...") }) 它不会返回任何内容,但使用 db.users.find({ _id: "..." }) 它会返回预期的用户。
我从头开始编写聚合查询以在 shell 上运行,这里是:
db.entities.aggregate([
{
$match: {
"active": "true",
}
},
{
$group: {
"_id" : {
$toString: "$user_id"
},
"EntityCount": { "$sum" : 1 }
}
},
{
$lookup: {
from: "users",
localField: "_id",
foreignField: "_id",
as: "UsersData"
}
},
{
$project: {
"_id": "$_id",
"EntityCount": "$EntityCount",
"UserData": {
"$arrayElemAt": ["$UsersData", 0]
},
}
},
{ $limit: 2 }
])
在 $group 阶段请注意,我将用户 ID 转换为字符串。如果我使用 "_id": "$user_id" 将无法工作。
最后一个阶段$limit 只是为了不炸毁控制台,从而更容易阅读结果。
这个查询执行得非常好。
返回 C#
这是 C# 驱动程序使用的最终查询:
[
{
"$match": {
"active": true,
}
},
{
"$group": {
"_id": "$user_id",
"EntityCount": {
"$sum":1
}
}
},
{
"$lookup": {
"from": "users",
"localField": "_id",
"foreignField": "_id",
"as": "users_data"
}
},
{
"$project": {
"UserId": "$user_id",
"EntityCount": "$EntityCount",
"UserData": {
"$arrayElemAt": ["$user_data", 0]
},
"_id": 0
}
}
]
我不知道为什么,但在 $group 阶段,UserId 字段被忽略(这解释了为什么它在结果中始终为空)。此外,您可以注意到 _id 在 $lookup 阶段被设置为 0。
我将字段 UserId 从 UserResult 重命名为 Id 并添加了属性 [BsonElement("_id")]。
现在,我在结果中同时获得了用户 ID 和实体计数,但 UserData 仍然为空。
【问题讨论】:
-
您是否建立了与 MongoDB 数据的 Mongodb 连接?你在使用 Newtonsoft.Json.Bson 和 MongoDB 库吗?
-
@IliassNassibane 连接正常。 MongoDB.Driver 的 nuget 版本是 2.9.2。我的 mongo 服务器是 4.2.3。我所有的操作都运行良好,除了这个聚合。
标签: c# mongodb aggregation-framework