猫鼬-最佳$ search自动完成

时间:2020-10-08 19:15:24

标签: node.js mongodb mongoose autocomplete aggregation-framework

我正在尝试使用$search基准线实现自动完成。 我想通过等待200毫秒并仅返回最新请求来减少服务器的工作量。

我该怎么做?我意识到我需要使用会话,但是语法和驱动程序功能尚不清楚

我要创建这个: flow chart of the process

1 个答案:

答案 0 :(得分:0)

在客户端,基本的解决方案,重要的是

  • 设置超时以在以后触发
  • 如果再次调用并且尚未通过超时
    • 然后清除超时并重新设置
  • 在时间过去之后让超时触发

有用的部分:

function defered(func, delay_call_after_ms) {
    var timeout=false;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            if(timeout)clearTimeout(timeout);
            func.apply(context, args);
        };
        timeout = setTimeout(later, delay_call_after_ms);
    };
};

var myfunction=defered(function(){
   //execute search here
}, 200)

完整示例: https://codepen.io/shimondoodkin/pen/LYZVEEO

var onsearchtimeout=false;
function onsearch() {
  if(onsearchtimeout) clearTimeout(onsearchtimeout);
  onsearchtimeout=setTimeout(search,200);
}
search_box.onchange=onsearch;
search_box.onkeyup=onsearch;


var xhr;
function search() {
  console.log("1")
  var xhr = createCORSRequest('GET', "https://runkit.io/shimondoodkin/cancel-request/branches/master?"+encodeURIComponent(search_box.value));
  xhr.onload = search_onload;
  xhr.onerror = function(e) { console.log("request error",e); };
  xhr.withCredentials = false;
  xhr.send();
}

function search_onload() {
  console.log(this.responseText);
  
  result=((JSON.parse(this.responseText)||{result:[]}).result||[]);
  console.log(result)
  search_autocomplete.innerHTML=
    
    result.map(x=>"<a tabindex=\"0\" onclick=\"search_box.value=this.innerText;hide();\" href=\"javascript://\">"+x.n+"</a>").join("<br>");
  search_autocomplete.focus();
  search_autocomplete.onblur=function(){
    setTimeout( function(){ hide();},200); }
}

function hide(){
  search_autocomplete.innerHTML="";
}

function createCORSRequest(method, url) {
  var xhr = new XMLHttpRequest();
  if ("withCredentials" in xhr) {
    // Most browsers.
    xhr.open(method, url, true);
  } else if (typeof XDomainRequest != "undefined") {
    // IE8 & IE9
    xhr = new XDomainRequest();
    xhr.open(method, url);
  } else {
    // CORS not supported.
    xhr = null;
  }
  return xhr;
};
<!--
btw 
position relative is the box that holds 
position absolute items
-->
<div style="display:inline-block;position:relative">

  <input id="search_box">

  <div id="search_autocomplete" tabindex="0" style="position:absolute;max-height:200px;overflow-y:scroll;background:white"></div>
</div>
<br>
type a  and wait long time
<br>
type a letter  and wait long time
        

在node.js服务器端,关闭和结束都有事件 在关闭时发生在结束之前断开连接。 当正常断开连接时会发生

在mongodb中,我不知道是否存在在连接期间获取当前操作ID的选项,也许可以对其进行调试和修改,然后创建一个将opid返回参数的函数。并再次返回。

但是有一个解决方案,可以在查询中添加评论,这将是我们的查询ID 那么就可以在正在运行的查询中进行搜索,并在节点js关闭事件上将其断开连接

https://runkit.com/shimondoodkin/cancel-request

var mongodb = require("mongodb")

const MongoClient = require('mongodb').MongoClient;
const uri = "mongodb+srv://test:test@cluster0.c3vbx.azure.mongodb.net/test?retryWrites=true&w=majority";
const client = new MongoClient(uri, { useNewUrlParser: true,
server: { auto_reconnect: true, socketOptions: {keepAlive: 1 }}
});

await client.connect();

const admindb=client.db("admin");
const testdb=client.db("test");
var n=0;

function kill(admindb,queryid)
{
 console.log("kill "+queryid)
 admindb.command({ currentOp: 1 }, function (err, result) {
       console.log(result.inprog)
       result.inprog.forEach(function(cop){
       if(cop.$comment===queryid)
          db.killOp(cop.opid)
     });
  });
}

//http.createServer(function (req, res) {
module.exports.endpoint = function(req, res) { 

 
 var queryid="q"+(n++);
var searchtext=(req.url.split('?',2)[1]||"");
  console.log("request "+searchtext)
  console.log({queryid});

 req.on("close", function() {
  // request closed unexpectedly
  console.log("request closed unexpectedly")
  kill(client.db("admin"),queryid)
 });
 
 //req.on("end", function() {
 //  // request ended normally
 //});
 
   
      const collection = testdb.collection("names");
      // perform actions on the collection object
      
      collection.find( { $query:{"n":{ 
      //$regex : "^"+searchtext
      $regex : searchtext
      }}, $comment:queryid }).toArray(function(err,result){ 
      
     console.log({a:"responded ok",result})
     
     res.setHeader("Access-Control-Allow-Origin", "*");
     res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
     res.writeHead(200);
     
     res.end(JSON.stringify({searchtext,result,err: err?(err.message?err.message:err)+"  "+(err.stack||""):""}));
     
     
      });
      
      //client.close(); 



}
//}).listen(80);