web-dev-qa-db-ja.com

全体として一致するプロジェクトがmongodbで機能しない

いくつかの一致条件に基づいてデータをフェッチしようとしています。最初に私はこれを試しました:ここでending_dateは完全な日付形式です

    Offer.aggregate([ 
    { 
        $match: { 
            carer_id : req.params.carer_id,
            status : 3
        }
    },
    {
        $group : {
            _id : { year: { $year : "$ending_date" }, month: { $month : "$ending_date" }}, 
            count : { $sum : 1 }
        }
    }], 
    function (err, res)
    { if (err) ; // TODO handle error 
         console.log(res); 
    });

これにより、次の出力が得られます。

[ { _id: { year: 2015, month: 11 }, count: 2 } ]

今、私は年もチェックしたいので、私はこれを試しています:

    Offer.aggregate([
    {
        $project: {
            myyear: {$year: "$ending_date"}
        }
    },
    { 
        $match: { 
            carer_id : req.params.carer_id,
            status : 3,
            $myyear : "2015"
        }
    },
    {
        $group : {
            _id : { year: { $year : "$ending_date" }, month: { $month : "$ending_date" }}, 
            count : { $sum : 1 }
        }
    }], 
    function (err, res)
    { if (err) ; // TODO handle error 
         console.log(res); 
    });

これにより、次の出力が得られます。

 []

ご覧のとおり、_idは2015年を年として持っているので、年と一致するときは配列になっているはずです。しかし、null配列を取得しています。なぜこれ?

日時全体から年のみを照合する他の方法はありますか?

これがサンプルデータです

{
    "_id": {
        "$oid": "56348e7938b1ab3c382d3363"
    },
    "carer_id": "55e6f647f081105c299bb45d",
    "user_id": "55f000a2878075c416ff9879",
    "starting_date": {
        "$date": "2015-10-15T05:41:00.000Z"
    },
    "ending_date": {
        "$date": "2015-11-19T10:03:00.000Z"
    },
    "amount": "850",
    "total_days": "25",
    "status": 3,
    "is_confirm": false,
    "__v": 0
}
{
    "_id": {
        "$oid": "563b5747d6e0a50300a1059a"
    },
    "carer_id": "55e6f647f081105c299bb45d",
    "user_id": "55f000a2878075c416ff9879",
    "starting_date": {
        "$date": "2015-11-06T04:40:00.000Z"
    },
    "ending_date": {
        "$date": "2015-11-16T04:40:00.000Z"
    },
    "amount": "25",
    "total_days": "10",
    "status": 3,
    "is_confirm": false,
    "__v": 0
}

後で$match$groupで使用しているフィールドを投影するのを忘れました。簡単に修正するには、代わりに次のクエリを使用してください。

Offer.aggregate([
{
    $project: {
        myyear: { $year: "$ending_date" },
        carer_id: 1,
        status: 1,
        ending_date: 1
    }
},
{ 
    $match: { 
        carer_id: req.params.carer_id,
        myyear: 2015,
        status: 3
    }
},
{
    $group: {
        _id: {
            year: { $year: "$ending_date" },
            month: { $month: "$ending_date" }
        }, 
        count: { $sum: 1 }
    }
}], 
function (err, res)
{
    if (err) {} // TODO handle error 
    console.log(res); 
});

そうは言っても、 Blakes Seven は、彼女の答えでより良いクエリを作成する方法を説明しました。代わりに彼女のアプローチを試してみるべきだと思います。

8

あなたはここで非常に多くの間違ったことをしているので、それは本当に説明が必要なので、うまくいけば何かを学ぶことができます。

そのパイプライン


これは最も基本的な概念ですが、集約の「パイプライン」がまさにそれであり、各ステージに入力をフィードする「パイプ」プロセスであるということを、ほとんどの人が(そして継続して使用した後でも)理解することはありません。に沿って。 「unixパイプ」と考える|

ps -ef | grep mongo | tee out.txt

あなたは間違いなく似たようなものを見たことがあります、そしてそれは最初のものからの出力が次のものに行きそして次に次のものに入力を与えるために操作するという基本的な概念です。

だからここにあなたが求めているものに関する基本的な問題があります:

    {
        $project: {
            myyear: {$year: "$ending_date"}
        }
    },
    { 
        $match: { 
            carer_id : req.params.carer_id,
            status : 3,
            $myyear : "2015"
        }
    },

ここで$projectが何をするかを考えてみましょう。出力に必要なフィールドを指定すると、フィールドが「吐き出され」、場合によっては操作されます。ドキュメント内のフィールドを「追加」してこれらのフィールドを出力しますか? いいえ、しません。あなたが出て欲しいものだけが実際に出てきて、次のパイプライン段階で使用することができます。

ここでの$matchは、出力で1つだけ要求したため、基本的には存在しなくなったフィールドを要求します。以前に削除したフィールドを再度要求すると、同じ問題がさらに発生します。参照するものは何もありませんが、$matchによってすべてがすでに削除されており、何にも一致しません。

また、それはあなたが入力したようにフィールドプロジェクションがどのように機能するかではありません

したがって、日付には範囲を使用してください


        { "$match": { 
            "carer_id" : req.params.carer_id,
            "status" : 3,
            "ending_date": { 
                "$gte": new Date("2015-01-01"), 
                "$lt": new Date("2016-01-01")
            }
        }},
        { "$group": {
            "_id": { 
                "year": { "$year": "$ending_date" }, 
                "month": { "$month": "$ending_date" }
            }, 
            "count": { "$sum": 1 }
        }}

どうして?それは理にかなっているからです。 「年」を一致させたい場合は、年間の日付範囲を指定します。抽出された年の値に一致するように$redactで愚かさを再生することもできますが、それは処理時間の無駄です。

この方法で処理するのが最も速く、実際にはインデックスを使用してより速く処理できます。したがって、問題を他のことを考えずに、必要な日付範囲を尋ねてください。

13
Blakes Seven