繁体   English   中英

MongoDB聚合。检查嵌套数组是否包含值

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM