最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to dynamically build MongoDB Query with multiple OR? - Stack Overflow

programmeradmin2浏览0评论

I would like to be able to dynamically build a Mongo query using Node with multiple OR's. The point of this query is to do an AND search in the database with multiple search terms.

For example, suppose someone wanted to search for records containing the words "dog" and "cereal." The query would only return records that have "dog" and "cereal" somewhere in the record (i.e. the search terms can appear in different columns).

I know that the query should end up looking like this:

query = {
    $and: [
        {$or: [
            {col1: {$regex: "first", $options: "i"}},
            {col2: {$regex: "first", $options: "i"}}
        ]},
        {$or: [
            {col1: {$regex: "second", $options: "i"}},
            {col2: {$regex: "second", $options: "i"}}
        ]}
    ]
}

My node code, however, does not produce this. This is the closest I have gotten to figuring this out:

var regexQueryWrapper = {};
regexQueryWrapper["$and"] = [];
var wrapper = {};
wrapper["$or"] = [];
var query = {};
searchTerms.forEach(function(term) {
    searchFields.forEach(function(field) {
        query[field] = {$regex: term, $options: 'i'};
        wrapper["$or"].push(query);
    });
    regexQueryWrapper["$and"].push(wrapper);
});

What is the best way to do this? Is there a different approach that I am missing?

I would like to be able to dynamically build a Mongo query using Node with multiple OR's. The point of this query is to do an AND search in the database with multiple search terms.

For example, suppose someone wanted to search for records containing the words "dog" and "cereal." The query would only return records that have "dog" and "cereal" somewhere in the record (i.e. the search terms can appear in different columns).

I know that the query should end up looking like this:

query = {
    $and: [
        {$or: [
            {col1: {$regex: "first", $options: "i"}},
            {col2: {$regex: "first", $options: "i"}}
        ]},
        {$or: [
            {col1: {$regex: "second", $options: "i"}},
            {col2: {$regex: "second", $options: "i"}}
        ]}
    ]
}

My node code, however, does not produce this. This is the closest I have gotten to figuring this out:

var regexQueryWrapper = {};
regexQueryWrapper["$and"] = [];
var wrapper = {};
wrapper["$or"] = [];
var query = {};
searchTerms.forEach(function(term) {
    searchFields.forEach(function(field) {
        query[field] = {$regex: term, $options: 'i'};
        wrapper["$or"].push(query);
    });
    regexQueryWrapper["$and"].push(wrapper);
});

What is the best way to do this? Is there a different approach that I am missing?

Share Improve this question asked Jul 12, 2017 at 22:04 sumowrestlersumowrestler 3655 silver badges21 bronze badges 2
  • Have you looked at using MongoDB's text search for this? Your use case sounds like a good fit. – JohnnyHK Commented Jul 12, 2017 at 22:13
  • @JohnnyHK I have and I would love to use it. But, it doesn't do like searching which is a requirement for the application. – sumowrestler Commented Jul 12, 2017 at 22:24
Add a ment  | 

2 Answers 2

Reset to default 3

You're close. You seem to be reusing objects. Here's some adjusted code that builds the query you're looking for, with the temporary objects reinitialized on each forEach iteration:

var regexQueryWrapper = {};
regexQueryWrapper["$and"] = [];

searchTerms.forEach(function(term) {

    var wrapper = {"$or": []};

    searchFields.forEach(function(field) {
        var query = {};
        query[field] = {$regex: term, $options: 'i'};
        wrapper["$or"].push(query);
    });

    regexQueryWrapper["$and"].push(wrapper);

});

And an alternative implementation using map:

var query = {"$and": searchTerms.map(function(term) {

    return {"$or": searchFields.map(function(field) {

        var o = {};
        o[field] = {"$regex": term, "$options": "i"};
        return o;

    })};

})};

I think you over plicated this.

Build your query step by step, by thinking about the the fact you are manipulating mostly two nested arrays (and and or).

With a function that pushes an array and another one that returns an array, NodeJS code would be:

query = {and: []};

function add_and(or_query) {
 query["and"].push({or: or_query});
}

function build_or_query(term) {
 return [
   {col1 : {$regex: term, $options: "i"}},
   {col2: {$regex: term, $options: "i"}}
 ]
}

Rename and use those functions as you see fit in your code to manage user input events. You can also merge them if you want to, ensuring very pact code:

function add_and(term) {
 query["and"].push({or: [
   {col1 : {$regex: term, $options: "i"}},
   {col2: {$regex: term, $options: "i"}}
 ]});
}

Use like (two functions) :

add_and(build_or_query('test1'));
add_and(build_or_query('test2'));

Or like (one function):

add_and('test1');
add_and('test2');

Result:

{ 
  and: [ 
    { or: [ { col1: { '$regex': 'test1', '$options': 'i' } },
            { col2: { '$regex': 'test1', '$options': 'i' } } ] },
    { or: [ { col1: { '$regex': 'test2', '$options': 'i' } },
            { col2: { '$regex': 'test2', '$options': 'i' } } ] } 
  ]
}
发布评论

评论列表(0)

  1. 暂无评论