[英]MongoDB Aggregation. Check if nested array contains value
我在实体中有这样的字段:
private String userId;
private String username;
private Date created;
private List<Comment> comments = new ArrayList<>();
Comment
有这样的领域:
private String userId;
private String username;
private String message;
private Date created;
我需要进行聚合,并收到类似这样的内容:
{
"userId" : "%some_userId%",
"date" : "%some_date%",
"commentsQty" : 100,
"isCommented" : true
}
我的聚合看起来像这样:
{ "aggregate" : "%entityName%" , "pipeline" : [
{ "$project" : {
"username" : 1 ,
"userId" : 1 ,
"created" : 1 ,
"commentQty" : { "$size" : [ "$comments"]}}}]}
它工作正常。 但我还需要检查,IF注释数组包含一些注释,具体的userId。 我尝试了这个,但它无法执行:
{ "aggregate" : "%entityName%" , "pipeline" : [
{ "$project" : {
"username" : 1 ,
"userId" : 1 ,
"created" : 1 ,
"commentQty" : { "$size" : [ "$comments"]} ,
"isCommented" : { "$exists" : [ "$comments.userId" , "5475b1e45409e07b0da09235"]}}}]}
有这样的消息: Command execution failed: Error [exception: invalid operator '$exists']
怎么做这样的检查?
UPD:还试过运营商$in
和类似的,但它们对于队列有效,而不是用于聚合。
有这样的消息:命令执行失败:错误[异常:无效的运算符'$ exists']
目前, $exists
运算符在aggregation
管道中不可用。
编辑:
写出更好的答案:
您可以通过以下方式检查是否有用户评论过:
$setIntersection
运算符来获取我们正在寻找的userId
的数组,如果用户真的对帖子发表了评论。 $size
运算符来获取结果数组的大小。 $gt
运算符检查大小是否大于0
。 userId
存在一个或多个注释,否则不存在。 示例代码:
var userIdToQuery = "2";
var userIdsToMatchAgainstComments = [ObjectId("5475b1e45409e07b0da09235")];
db.t.aggregate([
{$match:{"userId":userIdToQuery}},
{$project:{"userName":1,
"created":1,
"commentQty":{$size:"$comments"},
"isCommented":{$cond:
[{$gt:[
{$size:
{$setIntersection:["$comments.userId",
userIdsToMatchAgainstComments]}}
,0]},
true,false]}}}
])
上一个答案:
Unwind
评论。 Project
额外字段isCommented
对于每个评论文档,检查它是否具有我们正在搜索的userId
,如果它具有相应的userId
,则将该变量设置为1
else 0
。 Group
在一起,对isCommented
的值isCommented
,如果> 0
,则具有用户ID的文档不在组中。 Project
领域。 代码:
{ "aggregate" : "%entityName%" , "pipeline" :[
{$unwind:"$comments"},
{$project:{
"username":1,
"userId":1,
"created":1,
"comments":1,
"isCommented":{$cond:[{$eq:["$comments.userId",
ObjectId("5475b1e45409e07b0da09235")
]
},
1,
0]}}},
{$group:{"_id":{"_id":"$_id",
"username":"$username",
"userId":"$userId",
"created":"$created"},
"isCommented":{$sum:"$isCommented"},
"commentsArr":{$push:"$comments"}}},
{$project:{"comments":"$commentsArr",
"_id":0,
"username":"$_id.username",
"userId":"$_id.userId",
"created":"$_id.userId",
"isCommented":{$cond:[{$eq:["$isCommented",0]},
false,
true]},
"commentQty":{$size:"$commentsArr"}}},
]}
如果要检查确切的单个值(即特定的登录userId ),只需使用$in
运算符:
let loggedInUserId = "user1";
db.entities.aggregate([
{$project:{
"userName": 1,
"isCommentedByLoggedInUser": {
$in : [ loggedInUserId, "$comments.userId" ]
},
])
而已。
注意:如果你不希望每个文档都有注释数组,请用$ifNull
运算符包装它,并产生一个空数组:
$in : [ loggedInUserId, { "$ifNull": [ "$comments.userId", [] ] } ]
当您需要至少一个用户( 任何逻辑)中的一个来满足要求时,BatScream的答案就是检查多个值。 正如我所看到的那样,你的情况不是必需的,但它是一种很好的方式。
所以,BatScream以聚合方式提到了任何逻辑,我将以聚合方式继续使用所有逻辑。 要查找具有所有特定用户注释的文档,只需使用$setIsSubset
运算符:
let manyUsersIdsThatWeWantAll = ["user1", "user2", "user3"];
db.entities.aggregate([
{$project:{
"userName": 1,
"isCommentedByAllThoseUsers": {
$setIsSubset: [
manyUsersIdsThatWeWantAll, // the needle set MUST be the first expression
"$comments.userId"
]
},
])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.