使用 InsertOne/UpdateOne 在 DB 中添加值 - 如果找到以前的值;返回 NaN 而不是实际数字

Posted

技术标签:

【中文标题】使用 InsertOne/UpdateOne 在 DB 中添加值 - 如果找到以前的值;返回 NaN 而不是实际数字【英文标题】:Using InsertOne/UpdateOne to add value in DB - If previous value found; returns NaN instead of actual number 【发布时间】:2020-12-16 06:01:15 【问题描述】:

你好!

我目前正在尝试在我的 DiscordJS 机器人中使用“评分 1-5 星”功能。

我已经到了可以向 OneStar 添加值的地步(使用下图所示的命令)

它按预期向 OneStar 输入,因为这是管理员第一次被评为 1 星。

但是一旦我尝试向另一个对象添加一个值,比如 TwoStar - 它们返回为 NaN。

现在有趣的部分来了。 如果我决定先给 TwoStar 添加一个值(!rate admin @MENIX 2)

因为现在管理员有一个两星评级,它返回一个预期的值 - 但是如果我在添加到 OneStar 之后;那么现在将返回 NaN

这是该位的完整代码:

Functions.js:

AddRating: async function (UserID, toAdd) 
        const mclient = await MongoClient.connect(url, 
            useNewUrlParser: true,
            useUnifiedTopology: true
        ).catch(err => 
            console.log(err);
        );
        if (!mclient) return;
        try 
            const db = await mclient.db("DV");
            let collection = db.collection("rating")
            var res = await collection.find(
                id: UserID
            ).toArray()
            if (toAdd === "1") 
                if (res.length === 0) 
                    await collection.insertOne(
                        id: UserID,
                        OneStar: parseInt(1)
                    )
                 else 
                    var myquery = 
                        id: UserID
                    ;
                    var newvalues = 
                        $set: 
                            OneStar: parseInt(res[0].OneStar) + parseInt(1)
                        
                    ;

                    await collection.updateOne(myquery, newvalues)
                
            
            if (toAdd === "2") 
                if (res.length === 0) 
                    await collection.insertOne(
                        id: UserID,
                        TwoStar: parseInt(1)
                    )
                 else 
                    var myquery = 
                        id: UserID
                    ;
                    var newvalues = 
                        $set: 
                            TwoStar: parseInt(res[0].TwoStar) + parseInt(1)
                        
                    ;

                    await collection.updateOne(myquery, newvalues)
                
            
            if (toAdd === "3") 
                if (res.length === 0) 
                    await collection.insertOne(
                        id: UserID,
                        ThreeStar: parseInt(1)
                    )
                 else 
                    var myquery = 
                        id: UserID
                    ;
                    var newvalues = 
                        $set: 
                            ThreeStar: parseInt(res[0].ThreeStar) + parseInt(1)
                        
                    ;

                    await collection.updateOne(myquery, newvalues)
                
            
            if (toAdd === "4") 
                if (res.length === 0) 
                    await collection.insertOne(
                        id: UserID,
                        FourStar: parseInt(1)
                    )
                 else 
                    var myquery = 
                        id: UserID
                    ;
                    var newvalues = 
                        $set: 
                            FourStar: parseInt(res[0].FourStar) + parseInt(1)
                        
                    ;

                    await collection.updateOne(myquery, newvalues)
                
            
            if (toAdd === "5") 
                if (res.length === 0) 
                    await collection.insertOne(
                        id: UserID,
                        FiveStar: parseInt(1)
                    )
                 else 
                    var myquery = 
                        id: UserID
                    ;
                    var newvalues = 
                        $set: 
                            FiveStar: parseInt(res[0].FiveStar) + parseInt(1)
                        
                    ;

                    await collection.updateOne(myquery, newvalues)
                
            

         catch (err) 
            return err;
         finally 
            mclient.close();
        
    ,

我的想法是 - 我尝试将它们添加为 (Number(toAdd) 而不是 parseInt's - 但基本上不管我做什么,如果数据库中有一个预先存在的值;新的将返回 NaN .. 而不是它应该的实际值。

任何解决此问题的提示或想法将不胜感激。

我对 Mongo 或多或少有一半的新鲜感,但是在搜索了互联网之后 - 我不知道如何解决这个问题。

【问题讨论】:

您可能想查看 mongo 的 $inc 运算符,它用作 +,而不是每次都设置值 【参考方案1】:

这是因为您的响应正在检查用户对象,而您不再检查单个值,让我演示一下(我将立即使用失败案例):

var res = await collection.find( id: UserID ).toArray() //res is now an Array [userObj]

if (res.length === 0)  //false since there's something in the array
        await collection.insertOne(
            id: UserID,
            OneStar: parseInt(1)
        )
     else  //entering else now
        var myquery = 
            id: UserID
        ;
        var newvalues = 
            $set: 
                OneStar: parseInt(res[0].OneStar) //now trying to parse OneStar, this however is undefined => parseInt(undefined) results in NaN
            
        ;

        await collection.updateOne(myquery, newvalues)
    

您没有检查现有的评分数量。关于如何解决这个问题,您有两个选项:在创建用户对象时将所有 Ratings 设置为 0,或者添加对 undefined 的检查(也可以在 mongo 中使用 $inc 运算符,而不是每次都设置)。我将向您展示未定义的检查:

var newVals;
if(res[0].OneStar)
    newVals =  $inc:  OneStar: 1 ; //increase by one if already existing
 else 
    newVals =  $set:  OneStar: 1 ; //set to one if non-existing

除此之外,您的代码可以进行很多优化,因为除了 OneStar/TwoStar 等部分之外,大部分代码看起来都非常相似。您可以将它们保存为字符串并使用括号语法来访问像

这样的属性
let star = "OneStar";
res[0][star] ... //same as res[0].OneStar

但这只是一个旁注,我希望你明白一切

【讨论】:

非常感谢您的帮助 - 非常感谢!所以通读一遍,我非常感谢你清理了一些东西。我试图摆弄这些想法 - 但我认为我仍然走错了路。我添加了一点sn-p。我尝试添加一些控制台日志,但似乎代码实际上并没有进入 res[0][star] 位。 (我确实尝试过 (res[0].OneStar) )New code snippet 这可能是什么原因?我想我对这个问题完全视而不见 我认为我已经解决了 - 我继续添加所有 OneStar、TwoStar、ThreeStar 在数据库中创建时默认添加 & 只是决定使用 $inc 将它们从 0 > 开始增加。它似乎正在按我的预期工作,非常感谢您的指导! 没问题!这就是这个网站的目的!

以上是关于使用 InsertOne/UpdateOne 在 DB 中添加值 - 如果找到以前的值;返回 NaN 而不是实际数字的主要内容,如果未能解决你的问题,请参考以下文章

在哪里使用 CORBA 以及在哪里使用 SNMP 进行监控?

为啥在使用 unicode 时我不能在 :before :after 内容之后使用空格

在哪里使用 callable 以及在哪里使用 Runnable Interface?

在 Observable RxSwift 中使用 'asPromise()' 可以在 PromiseKit Promise 中使用吗?

可以在 SELECT 查询中使用 IF() 但不能在 UPDATE 中使用

使用 React,在使用 react-transition-group 时,在 StrictMode 中不推荐使用 findDOMNode 作为警告