【问题标题】:Building dynamic $match: for MongoDB aggregates构建动态 $match:用于 MongoDB 聚合
【发布时间】:2017-05-22 09:34:40
【问题描述】:

我正在尝试为我的 MongoDB 聚合构建动态 $match:

这是我希望我能做到的:

var matchStr = "";
if (req.body.propertyID) {
    matchStr += "property: { $in: properties },"
}
if (req.body.status=="ACTIVE" || req.body.status=="NOPAY") {
    matchStr += "status : {$lte: 4},"
} else if (req.body.status) {
    matchStr += "status : {$lte: req.body.status},"
}
matchStr += "checkin : {$gte: (checkin)}, checkout: {$lte: (checkout)}"

这就是我最终要做的:

它太乱了,现在我必须在 $match 中添加更多语句,这将使我的 if 结构更大。

必须有更好的方法来做到这一点!

我希望有人知道如何在没有“if hell :)”的情况下动态构建它们

if (req.body.propertyID & req.body.status=="ALL") {
    var matchStr = { 
        $match: {
            $and: 
            [{ 
                property: { $in: properties },
                checkin : {$gte: (checkin)}, 
                checkout: {$lte: (checkout)}    
            }]
        }
    }
} else if (!req.body.propertyID & !req.body.status) {
    var matchStr = { 
        $match: {
            $and: 
            [{ 
                checkin : {$gte: (checkin)}, 
                checkout: {$lte: (checkout)}    
            }]
        }
    }
} else if ((req.body.status=="ACTIVE" || req.body.status=="NOPAY")) {
    if (req.body.propertyID) { 
        var matchStr = { 
            $match: {
                $and: 
                [{ 
                    property: { $in: properties },
                    status : {$lte: 4}, 
                    checkin : {$gte: (checkin)}, 
                    checkout: {$lte: (checkout)}    
                }]
            }
        }
    } else {
        var matchStr = { 
            $match: {
                $and: 
                [{ 
                    status : {$lte: 4}, 
                    checkin : {$gte: (checkin)}, 
                    checkout: {$lte: (checkout)}    
                }]
            }
        }
    }
} else {
    if (req.body.propertyID) { 
        var matchStr = { 
            $match: {
                $and: 
                [{ 
                    property: { $in: properties },
                    status : {$lte: req.body.status}, 
                    checkin : {$gte: (checkin)}, 
                    checkout: {$lte: (checkout)}    
                }]
            }
        }
    } else {
        var matchStr = { 
            $match: {
                $and: 
                [{ 
                    status : {$lte: req.body.status}, 
                    checkin : {$gte: (checkin)}, 
                    checkout: {$lte: (checkout)}    
                }]
            }
        }
    }
}

更新! - 现在几乎明白了,除了它把“myMatch”放在 mongoDB 语句中。

这是新代码:

var myMatch = {
    checkin: {$gte: checkin},
    checkout: {$lte: checkout}
};

if (req.body.hasOwnProperty('propertyID')) {
    var properties = req.body.propertyID.map(function (obj) {
        return obj._id;
    });
    console.log("properties: " + properties); 
    myMatch["property"] = { "$in": properties };
}
if (req.body.status=="ACTIVE" || req.body.status=="NOPAY") {
    myMatch["status"] = { "$lte": 4 };
} else if (req.body.hasOwnProperty('status')) {
    myMatch["status"] = { "$lte": +req.body.status };
}

这是该结构的控制台日志:

myMatch: {
    "checkin": {
        "$gte": 1473571600
    },
    "checkout": {
        "$lte": 1596163600
    },
    "property": {
        "$in": [
            "PAP-720",
            "ATL-D406",
            "WAT-606"
        ]
    },
    "status": {
        "$lte": 3
    }
}

这里是我注入 myMatch 对象的地方:

    bookingTable.aggregate([
        {
            $match: {
                $and: 
                [{ 
                    myMatch
                }]
            }
        },

这是最后的 mongodb 语句:

Mongoose: 
booking.aggregate([ 
{ '$match': { '$and': [ { myMatch: { checkin: { '$gte': 1473571600 }, checkout: { '$lte': 1596163600 }, property: { '$in': [ 'PAP-720', 'ATL-D406', 'WAT-606' ] }, status: { '$lte': 3 } } } ] } },

【问题讨论】:

  • 对于初学者来说,checkincheckout 在每种情况下都始终存在,因此您可以只创建一个基础对象,因为向 JavaScript 对象添加属性很简单。其次,你听说过switch吗?无论您做什么,都不要再从字符串的角度思考问题,而是要学习一些有关对象操作的知识。
  • 这是一个结构更复杂的小例子,用几种不同的语言完成,但概念基本相同Generating a Structure for Aggregation
  • 是的,我可以下移签入和结帐,我还查看了$project 管道的示例,但我不太确定我是否理解它。它有点过头了。但看起来您可以将多个对象放入匹配中,而不仅仅是一个大字符串,对吗?
  • !叹息!好的,那么至少请回答我这个问题。您的 checkincheckout 都被上面的括号括起来。为什么?这些还不是数组吗?请说与$in 一起使用的properties 至少是一个数组。
  • @NeilLunn - 是的properties 是一个数组["AAA","BBB] 等等......我不确定你所说的签入是什么意思。我应该这样做吗? checkin : {$gte: checkin} ? (对不起,我还在努力学习这些结构是如何工作的:-))

标签: javascript node.js mongodb mongodb-query


【解决方案1】:

您真正需要注意的第一件事是,您几乎不需要编写显式的$and 语句。它有一个用法,但通常 MongoDB 查询中的 所有 表达式已经是“AND”操作。

接下来是解决方案看起来非常熟悉:

var myMatch = {
    checkin: checkin,
    checkout: checkout
};

if (req.body.propertyID) {
    myMatch["property"] = { "$in": properties };
}
if (req.body.status=="ACTIVE" || req.body.status=="NOPAY") {
    myMatch["status"] = { "$lte": 4 };
} else if (req.body.hasOwnProperty('status')) {
    myMatch["status"] = { "$lte": +req.body.status };
}

属性名称很正常,因此您可以交替使用:

    myMatch.property = { "$in": properties };

但这一切都归结为对 JavaScript 对象的基本操作。在任何动态类型语言中都几乎相同。

那你可以稍后再做:

{ "$match": myMatch }

它已经完成了。

【讨论】:

  • 啊啊啊啊!!!!!!我得到它!! - 因此,您可以简单地将每个子句视为对象 id,然后将参数添加到其中。如此简单 - 我不知道这是可能的。尼尔,如果这行得通,我可以从我的控制器上剪掉一千行 :-) 让我试一试,然后回复你 :)
  • req.body.hasOwnProperty['status'] 我不知道的那个 - 这是一种更优雅的方式来请求对象属性,而不仅仅是 !req.body.status 这似乎总是给我带来问题。
  • @torbenrudgaard 请注意,我基本上只是按照您关于构造字符串的想法,但更正操作对象。我已将最后一个else if 条件更改为1。)在这里测试“状态”属性的逻辑存在而不是返回值的“真实性”似乎更合乎逻辑。 2.) 鉴于之前针对状态的条件是数字("$lte": 4),那么“状态”应该是一个数字值也是合乎逻辑的。除非您在其上运行了正文解析器,否则 req.body 项目通常是字符串。所以+req.body.status 转换了。
  • 我尝试了if (req.body.hasOwnProperty['propertyID']) 而不是if (!req.body.propertyID),但它不起作用。 req.body 中的数据是:{"propertyID": [{"_id": "PAP-720", "_id": "ATL-D406"}]} 那为什么hasOwnProperty['propertyID'] 返回 undefined?
  • 咩括号错了 :-) if (req.body.hasOwnProperty('propertyID'))成功了 :)
猜你喜欢
  • 2017-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多