2017-06-05 78 views
0

我想编写一个小应用程序,在那里我可以存储传入的请求url,名为reqUrl,并使用compareUrls函数检查它是否已经存在。在MongoDB查询和变量范围内使用函数

如果两个网站都在同一个域中,则返回true,否则返回false,例如,在做compareUrls(stackoverflow.com, http://www.stackoverflow.com)时。这是为了避免添加重复的网址。

我试图使用该功能的MongoDB的查询里面是这样的:

app.get("/:reqUrl", function(req, res) 
{ 
    var reqUrl = req.params.reqUrl; 

    MongoClient.connect(Url, function(err, db) 
    { 
     if (err) throw err; 
     db.collection("mydb").find({$where: function() { 

     if (compareUrls(reqUrl, this.url) //if true, simply return the url 
     { 
      return this.url; 
     } else { //if not existing insert it into the database 
      db.collection("mydb").insert({"url":reqUrl}); 
     };   

    }}).toArray(); 

//Code continues below 

现在的问题是,因为作用域时,reqUrl变量不承认,我不知道任何解决办法。即使在使用局部变量compareUrls时,我也可以找回所有元素。我想通过简单地调用.find并检查reqUrl针对每个项目来恢复所有结果到一个数组,但是这远远超过了效率。

请注意,我对MongoDB非常陌生。

任何反馈将不胜感激,谢谢。

+0

'reqUrl'初始化在哪里? – Cynigo

+0

''MongoClient.connect()'外面的东西,我会编辑我的问题 – Valilutzik

+0

你不能在'$ where'函数内执行像'insert'这样的数据库操作。 – JohnnyHK

回答

1

这里的底线是,您不能在$where子句的逻辑内执行其他数据库操作,也不应该因为它是完全不必要的,并且您的操作在现有的标准操作符和方法中得到实际支持。

你是什么真的想要这里是.findOneAndUpdate()。你不需要$where来处理你正在做的匹配条件,那就是简单地检查一个值。这实际上是一个$regex“查询”部分选择的搜索条件。

至于“插入”部分,那么这就是"upserts"的用途。因此,当数据不是“找到”时,“upsert”会在集合中创建/插入新文档,否则当发现它“更新”时。你可以调整,在这种情况下,与$setOnInsert修改,使“未找到”文件实际上并没有修改,并且数据只触及了“插入”:

db.collection("mydb").findOneAndUpdate(
    { "url": new RegExp(reqUrl) }, 
    { "$setOnInsert": { "url": reqUrl } }, 
    { "upsert": true, "returnOriginal": false }, 
    function(err, doc) { 
    // deal with result here 
    } 
) 

当然这里的$regex使用仅仅是一个基本“是该字符串出现在属性字符串”“的条件中。还有更多高级正则表达式专用于“域匹配”,例如您可以在现有答案中找到:Regex to match simple domain

但基本逻辑保持不变,即“正则表达式”匹配条件,然后您只需“UPSERT”。

这就是说,实际上并没有任何东西阻止你使用$where子句作为匹配条件。这只是在实际操作中仍然是一个“UPSERT”,而不是试图以所谓的“内”所提供的功能的数据库方法,它可以调用一个server function或者是包括内联:

db.collection("mydb").findOneAndUpdate(
    { "$where": function() { return compareUrls(reqUrl, this.url); } }, 
    { "$setOnInsert": { "url": reqUrl } }, 
    { "upsert": true, "returnOriginal": false }, 
    function(err, doc) { 
    // deal with result here 
    } 
) 

只要确保的条件下$where服务器功能或任何结果实际上返回一个布尔值true/false,因为这是如何操作$where

此处还请注意"returnOriginal": false的用法,因为.findOneAndUpdate()方法的默认行为是在修改之前返回“原始”文档。在某些情况下,这是需要的,但最常见的用法是将文档返回到修改状态。

当然,如果您完全不需要文档作为响应,那么.updateOne()就足以作为一种方法,并且减少了“通过网络”返回文档内容的开销。

+0

非常感谢您的详细答案,我以前想过要走正则表达式路线,但我想绝对使用' compareUrls'函数。太糟糕了,它很难在MongoDB查询中使用自定义函数 – Valilutzik

+1

@Valilutzik这是非常多的设计。根本不是“太糟糕”。我无法想象你的函数中有任何事情不能用正则表达式来完成。事实上,如果这是您的唯一性测试,您可能应该将“域”存储为属性,那么这将成为一个简单的“平等”匹配和最高性能的选项。但是,你显然真的需要**来包装你的头脑,理解** JavaScript评估===坏**在性能和整个主机的原因方面。使用本地运营商。 –

+0

好吧,明白了:) – Valilutzik