Javascript Mongodb聚合管道新日期

Javascript Mongodb聚合管道新日期,javascript,node.js,mongodb,aggregation-framework,mongojs,Javascript,Node.js,Mongodb,Aggregation Framework,Mongojs,我尝试使用聚合管道根据以前的管道值追加/创建新日期,并保存到新集合(请参见下面的我的管道)。然而,语法是错误的,我得到了一个错误说 对象表达式中不允许的字段类型日期(“日期”)//日期:新日期(“$\u id.year”、“$\u id.month”、“$\u id.day”) 我想知道如何在mongo聚合管道中使用上一年、月、日的值来创建新日期?基本上,在将ISODate转换为年、月和日进行分组后,我想将它们转换回ISODate格式 pipeline = [{ $match: {

我尝试使用聚合管道根据以前的管道值追加/创建新日期,并保存到新集合(请参见下面的我的管道)。然而,语法是错误的,我得到了一个错误说

对象表达式中不允许的字段类型日期(“日期”)//日期:新日期(“$\u id.year”、“$\u id.month”、“$\u id.day”)

我想知道如何在mongo聚合管道中使用上一年、月、日的值来创建新日期?基本上,在将ISODate转换为年、月和日进行分组后,我想将它们转换回ISODate格式

pipeline = [{
    $match: {
        event: 'sample_event',
    }
}, {
    $project: {
        _id: false,
        uuid: '$properties.distinct_id',
        time: '$properties.time'
    }
}, {
    $group: {
        _id: {
            year: {
                $year: '$time'
            },
            month: {
                $month: '$time'
            },
            day: {
                $dayOfMonth: '$time'
            },
            uuid: '$uuid'
        }
    }
}, {
    $group: {
        _id: {
            year: '$_id.year',
            month: '$_id.month',
            day: '$_id.day'
        },
        value: { $sum: 1 }
    }
}, {
    $sort: {
        '_id.year': 1,
        '_id.month': 1,
        '_id.day': 1
    }
}, {
    $project: {
        _id: {
            $concat: [
                { $substr: ['$_id.year', 0, 4] },
                '-',
                {
                    $cond: [
                        { $lte: [ '$_id.month', 9 ] },
                        { $concat: [
                            '0',
                            { $substr: [ '$_id.month', 0, 2 ] }
                        ]},
                        { $substr: [ '$_id.month', 0, 2 ] }
                    ]
                },
                '-',
                {
                    $cond: [
                        { $lte: [ '$_id.day', 9 ] },
                        { $concat: [
                            '0',
                            { $substr: [ '$_id.day', 0, 2 ] }
                        ]},
                        { $substr: [ '$_id.day', 0, 2 ] }
                    ]
                },
            ]
        },
        date: new Date('$_id.year', '$_id.month', '$_id.day'), // errorrrr
        value: 1
    }
}, {
    $out: 'output_collection'
}];
不能在聚合管道中“强制转换”新数据类型。唯一真正允许的是使用整数值(而不是双精度)并从日期中提取时间戳值作为整数。但是字符串或数字不能成为字符串或日期对象中的数字

此外,在管道中实际上没有对JavaScript进行评估,您可能看到的任何示例都是纯粹的“单向旅行”,其中JavaScript函数在创建管道的文档中进行“评估”。但您不能让函数以任何方式对管道中的数据进行操作

编写新集合的最佳方法是处理游标结果并使用。因此,如果这是为了定期构建聚合结果,那么您甚至可以基本上附加或更新目标集合

这意味着使用底层本机驱动程序中的本机方法。使用mongojs的人看起来有点滑稽,但方法仍然存在:

var async=require('async'),
mongojs=require('mongojs'),
db=mongojs('mongodb://localhost/test“,[“样本]);
db.\u get(函数(err,db){
如果(错误)抛出错误;
var source=db.collection('source'),
bulk=db.collection('target')。initializeOrderedBulkOp(),
计数=0;
var cursor=source.aggregate(
[
{“$match”:{“事件”:“示例事件”},
{“$组”:{
“_id”:{
“日”:{
“$subtract”:[
{“$subtract”:[“$properties.time”,新日期(“1970-01-01”)],
{“$mod”:[
{“$subtract”:[“$properties.time”,新日期(“1970-01-01”)],
1000 * 60 * 60 * 24 
]}
]
},
“uuid”:“$properties.distinct\u id”
}
}}.
{“$group”:{“\u id”:“$\u id.day”,“count”:{“$sum”:1}}}
],
{“游标”:{“批大小”:101}
);
光标在(“数据”上,函数(数据){
bulk.insert({“date”:新日期(data.\u id),“count”:data.count});
计数++;
如果(计数%1000==0){
暂停();
bulk.execute(函数(错误、结果){
如果(错误)抛出错误;
bulk=db.collection('target')。initializeOrderedBulkOp();
cursor.resume();
});
}
});
cursor.on(“end”,function()){
如果(计数%1000!=0)
bulk.execute(函数(错误、结果){
控制台日志(“完成”);
});
});
});
因此,聚合操作大大简化,运行速度大大加快。输出是一个表示“天”的历元时间戳值,通过从另一个日期对象减去一个日期对象时,时间戳将作为整数返回。这里的常规日期数学将数字四舍五入为表示从提供的日期算起的“天”的值

这比强制字符串更有效,并且适合作为新日期对象的构造函数提供给
Date()
函数,当然,这是在聚合管道的“外部”完成的

这里的插入是批量执行的,每一千个项目只执行一次,因此非常高效。由于这实际上是一个流接口,因此您可以处理这些事件,并使用
.pause()
.resume()
来避免过多的并发请求和/或过多的内存使用。根据需要进行调优,但不管大小如何,驱动程序实际上会分解为1000个请求,用于任何一次发送和返回

当然,也可以在本阶段直接使用live而不将值强制转换为日期,然后使用
$out
创建集合,然后让代码根据读取的任何结果强制转换日期。但是,不能在聚合管道本身中操纵日期并以这种方式返回日期对象。使用任何最适合你的方法