web-dev-qa-db-ja.com

mongoose findを使用して文字列の一部を含むすべての値を取得する方法は?

Mongooseを使用してMongoDBからデータを取得する場合、次の問題があります。

これが私のスキーマです:

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

オブジェクトに2つの配列が埋め込まれていることがわかります。著者のコンテンツは次のようになります。authors:["Alex Ferguson"、 "Didier Drogba"、 "Cristiano Ronaldo"、 "Alex"]
私が達成しようとしているのは、アレイ内のすべてのアレックスを取得することです。

これまでのところ、値が完全に一致する場合に値を取得できました。しかし、Alexを含むものを取得しようとすると、答えは常に[]になります。

私が知りたいのは、map-reduceを実行してビューまたはコレクションを作成せずにfind()を使用してこれを実行し、その上にfind()を適用する方法です。

ここのコードは完全一致に対して機能します

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

            res.json(books);
        });

いくつか試してみましたが、運がありません{authors:{$ elemMatch:req.query.q}} {authors:{$ in:[req.query.q]}}

これは私にエラーを与え、その上に私がここで見つけた別の投稿では非常に非効率的だと言います。 {$ where:this.authors.indexOf(req.query.q)!= -1}

また、{authors:{$ regex: "./value/i"}}も試しました

Map-reduceは正常に機能します。どちらが優れているかを確認するには、他のアプローチを使用してmap-reduceを機能させる必要がありますか?

どんな助けも大歓迎です。これは簡単だと確信していますが、NodeJSとMongoは初めてなので、自分で理解することはできませんでした。

30
Dyan

あなたはタグで自分でこれにほぼ答えました。 MongoDBには $regex クエリとして正規表現を送信できるようにする演算子。したがって、「Alex」を含む文字列をクエリするには、次のようにします。

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

これも行うことができます:

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

    }
);

どちらも有効であり、ドキュメントに示されているように、サポートされている正しい構文で試行した方法とは異なります。

しかし、もちろん、実際に「文字列のどこかで「Alex」に一致するものだけの「配列」結果を取得する方法は?」これは少し異なります。

one以上の配列要素の複雑なマッチングは、 aggregation framework (または場合によってはmapReduceですが、それははるかに遅い)のドメインです。配列の内容を「フィルター」します。

ほぼ同じように開始します。ここで重要なのは $unwind は、個々のドキュメントとして適切に「フィルタリング」できるように、配列の内容を「非正規化」します。次に、「一致する」ドキュメントを使用して配列を再構築します。

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) {

    }
)
88
Neil Lunn