Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
617 views
in Technique[技术] by (71.8m points)

regex - How to get all the values that contains part of a string using mongoose find?

I have the following problem retrieving data from MongoDB using mongoose.

Here is my Schema:

const BookSchema = new Schema(
    {
        _id:Number,
        title:String,
        authors:[String],
        subjects:[String]   
    }
);

as you can see i have 2 arrays embedded in the object, let's say the content of the authors can be something like this: authors:["Alex Ferguson", "Didier Drogba", "Cristiano Ronaldo", "Alex"]
what I'm trying to achieve is get all the Alex in the array.

So far, I've been able to get the values if they match the value completely. However if I try to get the ones containing Alex the answer is always [].

What I want to know is how I can do this using find() without performing a map-reduce to create a view or a collection and then applying find() over that.

The code here works for exact matches

Book.find( {authors:req.query.q} , function(errs, books){
            if(errs){
                res.send(errs); 
            }

            res.json(books);
        });

I tried some things but no luck {authors:{$elemMatch:req.query.q}} {authors:{$in:[req.query.q]}}

This one gives me an error and on top of that says is very inefficient in another post I found here. {$where:this.authors.indexOf(req.query.q) != -1}

and I also tried {authors:{$regex:"./value/i"}}

The map-reduce works fine, I need to make it work using the other approach to see which one is better?

Any help is greatly appreciated. I'm sure this is easy, but I'm new with NodeJS and Mongo and I haven't been able to figure it out on my own.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You almost answered this yourself in your tags. MongoDB has a $regex operator which allows a regular expression to be submitted as a query. So you query for strings containing "Alex" you do this:

Books.find(
    { "authors": { "$regex": "Alex", "$options": "i" } },
    function(err,docs) { 
    } 
);

You can also do this:

Books.find(
    { "authors": /Alex/i }, 
    function(err,docs) { 

    }
);

Both are valid and different to how you tried in the correct supported syntax as shown in the documentation.

But of course if you are actually asking "how to get the 'array' results only for those that match 'Alex' somewhere in the string?" then this is a bit different.

Complex matching for more than one array element is the domain of the aggregation framework ( or possibly mapReduce, but that is much slower ), where you need to "filter" the array content.

You start of much the same. The key here is to $unwind to "de-normalize" the array content in order to be alble to "filter" properly as individual documents. Then re-construct the array with the "matching" documents.

Books.aggregate(
    [
        // Match first to reduce documents to those where the array contains the match
        { "$match": {
            "authors": { "$regex": "Alex", "$options": i }
        }},

        // Unwind to "de-normalize" the document per array element
        { "$unwind": "$authors" },

        // Now filter those document for the elements that match
        { "$match": {
            "authors": { "$regex": "Alex", "$options": i }
        }},

        // Group back as an array with only the matching elements
        { "$group": {
            "_id": "$_id",
            "title": { "$first": "$title" },
            "authors": { "$push": "$authors" },
            "subjects": { "$first": "$subjects" }
        }}
    ],
    function(err,results) {

    }
)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...