如何修改我的 mongodb/mongoose 查询,使其采用对象数组而不是字符串数组?

Posted

技术标签:

【中文标题】如何修改我的 mongodb/mongoose 查询,使其采用对象数组而不是字符串数组?【英文标题】:how can I modify my mongodb/mongoose query so that it takes array of objects instead of array of strings? 【发布时间】:2017-05-17 10:25:57 【问题描述】:

在我的应用中,我有一个 cmets 架构:

var CommentsSchema = new Schema(
    user_id: type: String, required: true, ref: 'users',
    text_content: type: String,
    is_anonymous: type: Boolean, default: false
);

现在我正在构建一个mongoose 查询以下载所有 cmets 并将其显示给用户。

由于我不想下载被最终用户屏蔽的用户的帖子,我介绍了一种排除来自被屏蔽作者的帖子的可能性:

var blockedUsers = req.body.blockedUsers;

function withBlockedUsers(query, blockedUsers) 
    if(blockedUsers != undefined)
        query.$and.push( 'user_id' :  $nin: blockedUsers  );
    

    return query;


var query = ;
query.$and = [];

query = withBlockedUsers(query, blockedUsers)
...
query = Comment.find(query);

query.exec(function(err, comments)
        if(err) 
            callback(err);
            return;
        
    return callback(null, comments);
    );

该代码有效,当我调用我的端点时,我需要向那里发送一个 string 被阻止用户 ID 的数组,并且他们的帖子将被排除在外。

现在我正在更改我的功能,而不是传递被阻止用户的 string 数组,而是传递对象数组:

 
 user_id: '586af425378c19fc044aa85f'
 is_anonymous: '0' 
,

当满足这两个条件时,我不想下载这些用户的帖子。

例如,当我的应用中有两个帖子时:


    user_id: '586af425378c19fc044aa85f',
    text_content: 'text1',
    is_anonymous: true
,

    user_id: '586af425378c19fc044aa85f', //same as above
    text_content: 'text2',
    is_anonymous: false

我通过blockedUsers对象:

 
 user_id: '586af425378c19fc044aa85f'
 is_anonymous: '0' 
,

作为回报,我只需要显示:


    user_id: '586af425378c19fc044aa85f',
    text_content: 'text1',
    is_anonymous: true
,

另一个帖子应该被屏蔽,因为user_id被识别并且is_anonymousfalse

使用我当前的代码出现错误:

message: 'Cast to string failed for value "[object Object]" at path "user_id"',名称:'CastError',种类:'string',值: user_id: '586af425378c19fc044aa85f', is_anonymous:'0' ,路径:'user_id',原因:未定义 路径“user_id”处的值“[object Object]”转换为字符串失败

【问题讨论】:

【参考方案1】:

您需要一种方法来构造一个使用 $nor 运算符的查询,该运算符对一个或多个查询表达式的数组以及所有查询表达式都失败的文档执行逻辑 NOR 运算在数组中返回。

例如,当你传递一个对象数组时,像

var blockedUsers = [
    
        user_id: '586af425378c19fc044aa85f'
        is_anonymous: '0' 
    ,
    
        user_id: '585808969e39db5196444c06'
        is_anonymous: '0' 
    ,
    
        user_id: '585808969e39db5196444c07'
        is_anonymous: '0' 
    
]

您的查询最终应该是

Comment.find(
    "$nor": [
        
            user_id: '586af425378c19fc044aa85f'
            is_anonymous: false 
        ,
        
            user_id: '585808969e39db5196444c06'
            is_anonymous: false
        ,
        
            user_id: '585808969e39db5196444c07'
            is_anonymous: false 
        
    ]
).exec(function(err, comments)
    if(err) 
        callback(err);
        return;
    
    return callback(null, comments);
);

所以任务是转换类似的东西

var blockedUsers = [
    
        user_id: '586af425378c19fc044aa85f'
        is_anonymous: '0' 
    ,
    
        user_id: '585808969e39db5196444c06'
        is_anonymous: '0' 
    ,
    
        user_id: '585808969e39db5196444c07'
        is_anonymous: '0' 
    
]

var query = 
    "$nor": [
        
            user_id: '586af425378c19fc044aa85f'
            is_anonymous: false 
        ,
        
            user_id: '585808969e39db5196444c06'
            is_anonymous: false
        ,
        
            user_id: '585808969e39db5196444c07'
            is_anonymous: false 
        
    ]

由于您要传入一个对象数组,因此您可以使用 map() 方法将 is_anonymous 值转换为布尔值,因此重构后的函数应如下所示:

function withBlockedUsers(query, blockedUsers) 
    var norOperator = [];
    if(blockedUsers != undefined)
        norOperator = blockedUsers.map(function(user)
            return 
                "user_id": user.user_id,
                "is_anonymous": (user.is_anonymous === '1')
            
        );
        query["$nor"] = norOperator;
    
    return query;

【讨论】:

@chrisdam 谢谢你很好的解释!我这里还有一个问题 - 我看到您正在比较 user.is_anonymous === '1',但在我的情况下,我可以使用 truefalse 发送标志。我的意思是用户 "user: '1234', "is_anonymous": true 应该被视为与 "user: '1234', "is_anonymous": false 不同的用户。我认为您的代码目前只检查标志是否等于true,对吗? 不,你在问题中说 现在我正在更改我的功能,而不是传递被阻止用户的字符串数组,而是传递对象数组: user_id: '586af425378c19fc044aa85f' is_anonymous: '0' , is_anonymous 标志是一个字符串,user.is_anonymous === '1' 部分将其转换为布尔值。现在您说您可以使用truefalse(不是字符串)发送标志,您能否相应地更新您的问题(相当混乱)?此外,如果您将数据作为布尔值发送,那么您可以更改部分 "is_anonymous": (user.is_anonymous === '1') "is_anonymous": user.is_anonymous) 并且查询应该可以工作。代码不仅检查is_anonymous 字段,而且检查user_idis_anonymous 字段,因为AND 逻辑是在表达式中指定逗号分隔值时隐式声明的,无需包含@ 987654348@运营商。

以上是关于如何修改我的 mongodb/mongoose 查询,使其采用对象数组而不是字符串数组?的主要内容,如果未能解决你的问题,请参考以下文章

mongodb -mongoose 增删查改

mongoDB (mongoose增删改查聚合索引连接备份与恢复监控等等)

如何使用 mongoose 将我的收藏放在 mongoDB 中?

如何填充递归模式引用 Mongodb、Mongoose、Express?

MongoDB(Mongoose)更新数组数组中的元素

单链查询 mongodb / mongoose 获取所有评论