Home Articles

MongoDB / Mongoose聚合或$或不按预期工作?

Asked
Viewed 413 times
1

在html中有一些复选框按钮,我想通过API on.click,通过AJAX过滤结果 . 有3种结果:upVoted,noVote,downVoted . 根据选中的复选框,将向用户显示upVoted,noVote和downVoted文档的组合 .

ajax调用API的URL,数据在node.js API中运行以下循环后正确到达数据库调用,该循环遍历字符串数组[“upVoted”,“noVote”,“downVoted” ](或其任意组合)并将布尔值true分配给相应的变量:

var upVoted = false;
var noVote = false;
var downVoted = false;
storyFiltering.forEach(storyFiltering);
function storyFiltering(element, index, array) {
    if (element == 'upVoted') {upVoted = true}
    else if (element == 'noVote') {noVote = true}
    else if (element == 'downVoted') {downVoted = true}
}
console.log('upVoted: ' + upVoted + ', noVote: ' + noVote + ', downVoted: ' + downVoted);

然后,这些变量与每个文档中的投票布尔值相匹配 .

这是数据库结构(投票只有一个布尔值一次是真的,其余的都是假的):

to: ["user1"],
voting: {
  upVoted: true,
  noVote: false,
  downVoted: false
},
rank: 4

to: ["user2"],
voting: {
  upVoted: true,
  noVote: false,
  downVoted: false
},
rank: 2

to: ["user1", "user2"],
voting: {
  upVoted: true,
  noVote: false,
  downVoted: false
},
rank: 1

to: ["user1", "user2"],
voting: {
  upVoted: false,
  noVote: true,
  downVoted: false
},
rank: 5

to: ["user1"],
voting: {
  upVoted: false,
  noVote: false,
  downVoted: true
},
rank: 3

查找(或聚合)的结果将是过滤的数据回调以匹配切换的投票布尔值...然后通过降序'rank'对它们进行排序 .

切换user1的所有upVoted和noVote文档将返回:

to: ["user1", "user2"],
voting: {
  upVoted: true,
  noVote: false,
  downVoted: false
},
rank: 1

to: ["user1"],
voting: {
  upVoted: true,
  noVote: false,
  downVoted: false
},
rank: 4

to: ["user1", "user2"],
voting: {
  upVoted: false,
  noVote: true,
  downVoted: false
},
rank: 5

..仅为user1切换upVote文件将返回:

to: ["user1", "user2"],
voting: {
  upVoted: true,
  noVote: false,
  downVoted: false
},
rank: 1

to: ["user1"],
voting: {
  upVoted: true,
  noVote: false,
  downVoted: false
},
rank: 4

..并且在相同的模式中,为用户1切换所有upVoted noVote downVoted文档将返回包含用户1的所有文档,按等级(1,3,4,5)排序..同时,有意义地,切换对于用户2的所有downVoted文档将返回零文档 .

1 Answer

  • 1

    在我看来,这是你的方法的基本问题 . 您要做的是与用户界面进行交互,该用户界面“选择”您希望在查询结果中显示的某些项目 . 这一切都很好,但很明显,你似乎在寻找“一个查询来统治所有人”,这就是你解开的地方 .

    以您的第一个示例为例,您对所有"upvote"和"novote"文档的查询都是这样的 . 现在还要说明聚合,但同样适用于对$match管道的查询:

    db.collection.find({
        "to": { "$in": ["user1"] },
        "$or": [
            { "voting.upVoted": true },
            { "voting.noVote": true }
        ]
    })
    

    这将返回您的预期结果,因为$or认为这些条件的"either"可以评估为 true 以满足匹配 . 如前所述,MongoDB中的所有查询都隐式地是"and"查询,因此这里不需要额外的运算符 .

    在你的下一个例子中,你真的只需要 one 你的标准是真的,所以我们可以删除$or但是我会留在这里以便稍后解释 .

    db.collection.find({
        "to": { "$in": ["user1"] },
        "$or": [
            { "voting.upVoted": true }
        ]
    })
    

    再次匹配您的预期结果,因为它返回"user1"存在的位置"and" "upVoted"值为 true .

    但现在进入您的界面交互以及如何处理它 . 让我们说你有来自你的界面的输入看起来像这样:

    {
       "to": "user1",
       "voting": {
          "upVoted": true,
          "downVoted": false,
          "noVote": true
       }
    }
    

    这确认了您在用户界面中为查询所做的基本选择 . 为了将"process"这个放入您想要的查询中,请考虑以下JavaScript代码,将其翻译成您想要实现的任何语言 . 我只是假设所显示的结构位于一个名为 request 的变量中:

    var query = {
        "to": { "$in": [] },
        "$or": []
    };
    
    for ( k in request ) {
        if ( k == "to" )
            query.to["$in"].push( request.to );
    
        if ( k == "voting" ) {
            for ( v in request[k] ) {
                if ( request[k][v] ) {      // if that value is `true`
                    var obj = {};
                    obj[ k + "." + v] = true;
                    query["$or"].push( obj );
                }
            }
        }
    }
    

    在该数据上运行代码,生成的 query 对象现在看起来像:

    {
        "to" : {
                "$in" : [
                        "user1"
                ]
        },
        "$or" : [
                {
                        "voting.upVoted" : true
                },
                {
                        "voting.noVote" : true
                }
        ]
    }
    

    这与我们首先发出的查询相同,并在 request 中更改您的选择以查看第二个示例中的选择:

    {
       "to": "user1",
       "voting": {
          "upVoted": true,
          "downVoted": false,
          "noVote": false
       }
    }
    

    生成的 query 对象是:

    {
        "to" : {
                "$in" : [
                        "user1"
                ]
        },
        "$or" : [
                {
                        "voting.upVoted" : true
                }
        ]
    }
    

    剩下要做的就是发出使用对象作为参数的查询:

    db.collection.find( query )
    

    这就是您与界面中的数据进行交互的方式 . 您可以动态构建,而不是尝试将 response 中获得的所有值作为查询中的参数 .

Related