草庐IT

MongoDB,原子级操作

coder 2023-10-31 原文

我想在 MongoDB 中询问一些与 findAndModify 相关的信息。
据我所知,查询是“由文档隔离的”。
这意味着,如果我像这样运行 2 findAndModify:

{a:1},{set:{status:"processing", engine:1}}
{a:1},{set:{status:"processing", engine:2}}
并且这个查询可能会影响 2.000 个文档,因为有 2-query (2engine) 那么也许某个文档会有“engine:1”和另一个“engine:2”。
我认为 findAndModify 不会隔离“第一个查询”。
为了隔离第一个查询,我需要使用 $isolated。
一切都写我所写的吗?
更新 - 场景
这个想法是编写一个接近引擎。
集合 User 有 1000-2000-3000 个用户,或数百万。
1 - 从点“lng,lat”按最近的顺序排序
2 - 在 NodeJS 中,我做了一些我无法在 MongoDB 中进行的计算
3 - 现在我将用户分组到“用户组”中,然后我写了一个批量更新
当我有 2000-3000 个用户时,这个过程(从 1 到 3)需要时间。
所以我想并行使用多线程。
并行线程意味着并行查询。
这可能是一个问题,因为 Query3 可能会占用 Query1 的一些用户。
如果发生这种情况,那么在点 (2) 处,我没有最接近的用户,而是最接近“此查询”的用户,因为可能另一个查询已经占用了其余的用户。这可能会造成纽约的某些用户与洛杉矶的用户分组在一起。
更新 2 - 场景
我有一个这样的集合:
{location:[lng,lat], name:"1",gender:"m", status:'undone'}
{location:[lng,lat], name:"2",gender:"m", status:'undone'}
{location:[lng,lat], name:"3",gender:"f", status:'undone'}
{location:[lng,lat], name:"4",gender:"f", status:'done'}
我应该能够做的是通过按最近的分组来创建用户的“组”。每组有1男+1女。在上面的例子中,我期望只有 1 个组(用户 1+用户 3),因为有男性+女性并且彼此如此接近(用户 2 也是男性,但远离用户 3 和用户-4 也是女性,但状态为“完成”,因此已经处理)。
现在创建了组(只有 1 个组),因此 2 个用户被标记为“完成”,而另一个用户 2 被标记为“撤消”以供将来操作。
我希望能够非常快速地管理 1000-2000-3000 个用户。
更新 3:来自社区
现在好了。我可以试着总结一下你的情况。给定您的数据,您希望根据彼此的接近程度将男性和女性条目“配对”在一起。大概你不想做所有可能的匹配,而只是设置一个一般“推荐”列表,假设每个用户最近的位置有 10 个。现在我必须愚蠢才能看不到这一切的完整方向,但这是否总结了基本的初始问题陈述。处理每个用户,找到他们的“配对”,配对后将它们标记为“完成”,并在完成时通过组合将它们从其他配对中排除?

最佳答案

这是一个不平凡的问题,不容易解决。

首先,迭代方法(无可否认是我的第一个方法)可能会导致错误的结果。

鉴于我们有以下文件

{
   _id: "A",
   gender: "m",
   location: { longitude: 0, latitude: 1 }
 }

 {
   _id: "B",
   gender: "f",
   location: { longitude: 0, latitude: 3 }
 }

 {
   _id: "C",
   gender: "m",
   location: { longitude: 0, latitude: 4 }
 }

 {
   _id: "D",
   gender: "f",
   location: { longitude: 0, latitude: 9 }
 }

使用迭代方法,我们现在将从“A”开始并计算最近的女性,当然这将是距离为 2 的“B”。但是,实际上,男性和女性之间的最近距离是1(从“B”到“C”的距离)。但即使我们找到了这一点,这也会使另一场比赛“A”和“D”的距离为 8,而根据我们之前的解决方案,“A”与“B”的距离仅为 2 .

所以我们需要决定走哪条路
  • 天真地遍历文档
  • 找到匹配个体之间的最小距离总和(这本身并不容易解决),以便所有参与者一起拥有最短的行程。
  • 仅匹配可接受距离内的参与者
  • 在公共(public)地标(例如城市)的特定半径内进行某种分而治之并匹配参与者

  • 解决方案 1:天真地迭代文档
    var users = db.collection.find(yourQueryToFindThe1000users);
    
    // We can safely use an unordered op here,
    // which has greater performance.
    // Since we use the "done" array do keep track of
    // the processed members, there is no drawback.
    var pairs = db.pairs.initializeUnorderedBulkOp();
    
    var done = new Array();
    
    users.forEach(
      function(currentUser){
    
         if( done.indexOf(currentUser._id) == -1 ) { return; }
    
         var genderToLookFor = ( currentUser.gender === "m" ) ? "f" : "m";
    
         // using the $near operator,
         // the returned documents automatically are sorted from nearest
         // to farest, and since findAndModify returns only one document
         // we get the closest matching partner.
         var nearPartner = db.collection.findAndModify(
           query: {
             status: "undone",
             gender: genderToLookFor,
             $near: {
               $geometry: {
                 type: "Point" ,
                 coordinates: currentUser.location
               }
             }
           },
           update: { $set: { "status":"done" } },
           fields: { _id: 1}
         );
    
         // Obviously, the current use already is processed.
         // However, we store it for simplifying the process of
         // setting the processed users to done.
         done.push(currentUser._id, nearPartner._id);
    
         // We have a pair, so we store it in a bulk operation
         pairs.insert({
           _id:{
             a: currentUser._id,
             b: nearPartner._id
           }
         });
    
      }
    )
    
    // Write the found pairs
    pairs.execute();
    
    // Mark all that are unmarked by now as done
    db.collection.update(
      {
        _id: { $in: done },
        status: "undone"
      },
      {
        $set: { status: "done" }
      },
      { multi: true }
    )
    

    解决方案 2:找到匹配项之间的最小距离总和

    这将是理想的解决方案,但解决起来极其复杂。我们需要对一种性别的所有成员,计算与另一种性别的所有成员的所有距离,并迭代所有可能的匹配集。在我们的示例中,它非常简单,因为任何给定的性别只有 4 种组合。仔细想想,这可能至少是旅行商问题(MTSP?)的一个变体。如果我是对的,组合的数量应该是

    对于所有 n>2,其中 n 是可能的对数。

    因此

    对于 n=10

    和一个惊人的

    对于 n=25

    那是 7.755 千万亿(长尺度)或 7.755 千分之一(短尺度)。
    虽然有解决此类问题的方法,但世界纪录大约是 25,000 个节点,使用大量硬件和相当棘手的算法。我认为出于所有实际目的,可以排除这种“解决方案”。

    解决方案3

    为了防止人们可能与他们之间的 Not Acceptable 距离以及根据您的用例进行匹配的问题,您可能希望根据人们与公共(public)地标(他们将要见面的地方,例如下一个更大的地点)的距离来匹配人们城市)。

    对于我们的示例,假设我们在 [0,2] 和 [0,7] 处有城市。因此,城市之间的距离 (5) 必须是我们可接受的匹配范围。所以我们对每个城市做一个查询
    db.collection.find({
     $near: {
       $geometry: {
         type: "Point" ,
         coordinates: [ 2 , 0 ]
       },
       $maxDistance: 5
     }, status: "done"
    })
    

    并天真地迭代结果。由于“A”和“B”将是结果集中的第一个,因此它们将被匹配并完成。这里的“C”运气不好,因为没有女孩留给他。但是当我们对第二个城市做同样的查询时,他得到了第二次机会。好吧,他的旅行时间有点长,但是嘿,他和“D”约会了!

    要找到各自的距离,请选取一组固定的城市(城镇、大都市区,无论您的规模如何),按位置对它们进行排序,并将每个城市的半径设置为与其直接邻居的两个距离中较大的一个。这样,您会得到重叠区域。因此,即使在一个地方找不到匹配项,也可能在其他地方找到。

    Iirc,谷歌地图允许它根据一个国家的大小来抓取一个国家的城市。更简单的方法是让人们选择他们各自的城市。

    笔记
  • 显示的代码不是生产就绪的,需要改进。
  • 我建议使用 1 和 0,而不是使用“m”和“f”来表示性别:仍然可以轻松映射,但需要更少的空间来保存。
  • 状态也是一样。
  • 我认为最后一个解决方案是最好的,优化距离并保持较高的比赛机会。
  • 关于MongoDB,原子级操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32284811/

    有关MongoDB,原子级操作的更多相关文章

    1. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

      我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

    2. ruby-on-rails - 如何处理 Grape 中特定操作的过滤器之前? - 2

      我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?

    3. ruby-on-rails - 在 Ruby on Rails 中发送响应之前如何等待多个异步操作完成? - 2

      在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.

    4. ruby - 在 Ruby 中是否有一种惯用的方法来操作 2 个数组? - 2

      a=[3,4,7,8,3]b=[5,3,6,8,3]假设数组长度相同,是否有办法使用each或其他一些惯用方法从两个数组的每个元素中获取结果?不使用计数器?例如获取每个元素的乘积:[15,12,42,64,9](0..a.count-1).eachdo|i|太丑了...ruby1.9.3 最佳答案 使用Array.zip怎么样?:>>a=[3,4,7,8,3]=>[3,4,7,8,3]>>b=[5,3,6,8,3]=>[5,3,6,8,3]>>c=[]=>[]>>a.zip(b)do|i,j|c[[3,5],[4,3],[7,6],

    5. ruby-on-rails - 如何让 Rails View 返回其关联的操作名称? - 2

      我有一个非常简单的Controller来管理我的Rails应用程序中的静态页面:classPagesController我怎样才能让View模板返回它自己的名字,这样我就可以做这样的事情:#pricing.html.erb#-->"Pricing"感谢您的帮助。 最佳答案 4.3RoutingParametersTheparamshashwillalwayscontainthe:controllerand:actionkeys,butyoushouldusethemethodscontroller_nameandaction_nam

    6. HarmonyOS原子化服务开发相关术语 - 2

      术语中文解释Ability原子化服务帮助用户完成任务的原子化服务,和用户的意图进行关联。Fulfillment服务履行通过图标,卡片,语音等形式呈现用户意图。开发者通过接口的方式,处理用户意图,返回内容。Intent意图用于表达用户想要达成的目标或完成的任务。HUAWEIAssistant智能助手“无微不智”的个人助手,通过不断的学习用户的使用习惯,不断的为用户提供贴心的精准的便捷的个性化服务。AISearch全局搜索用户可快速搜索关键词,与之匹配的原子化服务则会出现在搜索结果中。SmartService智慧服务用户订阅原子化服务,在到达特定触发条件(时间、地点、事件)后,卡片推送至用户智能助

    7. Postman测试简单操作 - 2

      1、接口请求基本操作1.1例子tips在view的选项可以zoomin调整窗口字帖大小。1、创建一个测试的workspace,并命名为test2、test后面新增一个addrequest3、选择发送GET,URL为一个开源的https://api.apiopen.top/api/sentences获取每日一句4、点击send查看内容Tips:如果提示出现Error:tunnelingsocketcouldnotbeestablished,statusCode=407错误,参照以下解决办法)关于tunnelingsocketcouldnotbeestablished,cause=getaddri

    8. 【Linux操作系统】——网络配置与SSH远程 - 2

      Linux操作系统——网络配置与SSH远程安装完VMware与系统后,需要进行网络配置。第一个目标为进行SSH连接,可以从本机到VMware进行文件传送,首先需要进行网络配置。1.下载远程软件首先需要先下载安装一款远程软件:FinalShell或者xhell7FinalShellxhell7FinalShell下载:Windows下载http://www.hostbuf.com/downloads/finalshell_install.exemacOS下载http://www.hostbuf.com/downloads/finalshell_install.pkg2.配置CentOS网络安装好

    9. ruby - Ruby 语言可以用来构建操作系统吗? - 2

      Ruby语言是否可以用于创建全新的移动操作系统或桌面操作系统,即是否可以用于系统编程? 最佳答案 嗯,现在有一些操作系统使用比C更高级的语言。基本上,ruby解释器本身需要用一些低级的东西来编写,并且需要一些引导加载代码将功能齐全的ruby​​解释器作为独立内核加载到内存中。一旦ruby​​解释器被引导并以内核模式(或innerrings之一)运行,就没有什么可以阻止您在其上构建整个操作系统。不幸的是,它可能会很慢。每个操作系统功能的垃圾收集可能会相当引人注目。ruby解释器将负责任务调度和网络堆栈等基本事情,使用垃圾收集框架会大大

    10. ruby-on-rails - JSON 对象操作 - 2

      假设我们有以下描述一个人的JSON对象:{"firstName":"John","lastName":"Smith","age":25,"address":{"streetAddress":"212ndStreet","city":"NewYork","state":"NY","postalCode":"10021"},"phoneNumber":[{"type":"home","number":"212555-1234"},{"type":"fax","number":"646555-4567"}]有人可以建议在Rails3中操作前一个对象的最优雅和最有效的方法吗?我希望能够:添加另

    随机推荐