Mongodb子文档搜索并选择

时间:2015-04-17 11:40:58

标签: node.js mongodb

我有这种结构的mongo数据库:

Collection structure

我需要在时间范围之间获取父文档及其子文档。 我使用nodejs mongoosejs驱动程序。这是我目前的要求:

    var searchQueryTerminal = TickModel
    .findOne({
        symbol:symbol,
        'tickData.timestamp':{
            $gte:dateStart,
            $lte:dateEnd
        },
        broker:{$in: broker},
        MTVersion:MTVersion
    });

我在结果中有1个父文档,正如预期的那样,但它包含所有子文档,不仅包括时间范围。如何使用猫鼬驱动程序以正确的方式执行此操作?我不是真的想在节点端做这件事,因为子文档的数量可能是几百万。

架构:

var TickDataSchema   = new mongoose.Schema({
bid: Number,
ask: Number,
timestamp: {
    type:Date,
    default:Date.now,
    expires: '7d'
}});


var TickSchema   = new mongoose.Schema({
    broker:{
        type: String,
        index:true
    },
    account: Number,
    symbol: {
        type: String,
        index:true
    },
    MTVersion:Number,
    key: {
    type:String,
        index:true
    },
    tickData:[TickDataSchema]
});

2 个答案:

答案 0 :(得分:1)

使用implementation的Mongoose $elemMatch 。在mongo中使用以下集合进行测试:

db.test.insert([
    { "symbol": "AMBC", "MTVersion": 0.25, "tickData": [{ "bid": 1, "ask": 1.5, "timestamp": ISODate("2015-01-28T08:00:00.000Z") }, { "bid": 1, "ask": 1.3, "timestamp": ISODate("2015-01-21T08:00:00.000Z") }] },
    { "symbol": "MSFT", "MTVersion": 0.25, "tickData": [{ "bid": 1, "ask": 1.5, "timestamp": ISODate("2015-02-04T08:00:00.000Z") }, { "bid": 1, "ask": 1.3, timestamp: ISODate("2015-02-11T08:00:00.000Z") }] }
]);

var symbol = "AMBC",
    dateStart = new Date (2015, 0, 20),
    dateEnd = new Date(2015, 0, 22),
    MTVersion = 0.25;

db.test.findOne({
    "symbol": symbol,
    "tickData.timestamp": {
        "$gte": dateStart,
        "$lte": dateEnd
    },    
    "MTVersion": MTVersion
}, {
    "symbol": 1,
    "MTVersion": 1,
    "tickData": {
        "$elemMatch": {
            "timestamp": {
                "$gte": dateStart,
                "$lte": dateEnd
            }
        }
    }
});

<强>返回

/* 0 */
{
    "_id" : ObjectId("5530f8c4180e849972938fdf"),
    "symbol" : "AMBC",
    "MTVersion" : 0.25,
    "tickData" : [ 
        {
            "bid" : 1,
            "ask" : 1.3,
            "timestamp" : ISODate("2015-01-21T08:00:00.000Z")
        }
    ]
}

所以在Mongoose中,你可以做类似的事情:

TickModel
    .findOne({
        symbol: symbol,
        broker: {$in: broker},
        MTVersion: MTVersion
    })
    .elemMatch("tickData", { "timestamp": {"$gte": dateStart, "$lte": dateEnd } })
    // .select({"tickData": { "$elemMatch": { "timestamp": {"$gte": dateStart, "$lte": dateEnd } }, "symbol": 1, "MTVersion": 1, "broker": 1 })
    .exec(cb);

使用聚合框架,可以通过以下管道实现:

var pipeline = [
    {
        "$match": {
            "symbol": symbol,
            "tickData.timestamp": {
                "$gte": dateStart,
                "$lte": dateEnd
            },    
            "MTVersion": MTVersion
        }
    },
    {
        "$unwind": "$tickData"
    },
    {
        "$match": {            
            "tickData.timestamp": {
                "$gte": dateStart,
                "$lte": dateEnd
            }
        }
    },
    {
        "$group": {
            _id: {
                "id": "$_id",
                "broker": "$broker",
                "account": "$account"
                "symbol": "$symbol",
                "MTVersion": "$MTVersion",
                "key": "$key"
            },
            "tickData": {
                "$addToSet": "$tickData"
            }
        }
    },
    {
        "$project": {
            "_id": 0,
            "tickData": 1,
            "broker": "$_id.broker",
            "account": "$_id.account"
            "symbol": "$_id.symbol",
            "MTVersion": "$_id.MTVersion",
            "key": "$_id.key"
        }
    }
];
TickModel.aggregate(pipeline, function (err, result) {
        if (err) {
            console.log(err);
            return;
        }
        console.log(result);
    });

结果:(使用上述样本文件)

/* 0 */
{
    "result" : [ 
        {
            "tickData" : [ 
                {
                    "bid" : 1,
                    "ask" : 1.3,
                    "timestamp" : ISODate("2015-01-21T08:00:00.000Z")
                }
            ],
            "symbol" : "AMBC",
            "MTVersion" : 0.25
        }
    ],
    "ok" : 1
}

答案 1 :(得分:0)

您可以尝试填充功能

 var searchQueryTerminal = TickModel
    .findOne({
        symbol:symbol,
        broker:{$in: broker},
        MTVersion:MTVersion
    }).populate({
        path: 'tickData',
        match: { timestamp: { $gte:dateStart, $lte:dateEnd}},
    })