@@ -106,6 +106,41 @@ Aggregate.prototype.append = function() {
106
106
return this ;
107
107
} ;
108
108
109
+ /**
110
+ * Appends a new $addFields operator to this aggregate pipeline.
111
+ * Requires MongoDB v3.4+ to work
112
+ *
113
+ * ####Examples:
114
+ *
115
+ * // adding new fields based on existing fields
116
+ * aggregate.addFields({
117
+ * newField: '$b.nested'
118
+ * , plusTen: { $add: ['$val', 10]}
119
+ * , sub: {
120
+ * name: '$a'
121
+ * }
122
+ * })
123
+ *
124
+ * // etc
125
+ * aggregate.addFields({ salary_k: { $divide: [ "$salary", 1000 ] } });
126
+ *
127
+ * @param {Object } arg field specification
128
+ * @see $addFields https://docs.mongodb.com/manual/reference/operator/aggregation/addFields/
129
+ * @return {Aggregate }
130
+ * @api public
131
+ */
132
+ Aggregate . prototype . addFields = function ( arg ) {
133
+ var fields = { } ;
134
+ if ( typeof arg === 'object' && ! util . isArray ( arg ) ) {
135
+ Object . keys ( arg ) . forEach ( function ( field ) {
136
+ fields [ field ] = arg [ field ] ;
137
+ } ) ;
138
+ } else {
139
+ throw new Error ( 'Invalid addFields() argument. Must be an object' ) ;
140
+ }
141
+ return this . append ( { $addFields : fields } ) ;
142
+ } ;
143
+
109
144
/**
110
145
* Appends a new $project operator to this aggregate pipeline.
111
146
*
@@ -625,26 +660,27 @@ Aggregate.prototype.exec = function(callback) {
625
660
throw new Error ( 'Aggregate not bound to any Model' ) ;
626
661
}
627
662
var _this = this ;
663
+ var model = this . _model ;
628
664
var Promise = PromiseProvider . get ( ) ;
629
- var options = utils . clone ( this . options ) ;
665
+ var options = utils . clone ( this . options || { } ) ;
666
+ var pipeline = this . _pipeline ;
667
+ var collection = this . _model . collection ;
630
668
631
669
if ( options && options . cursor ) {
632
670
if ( options . cursor . async ) {
633
671
delete options . cursor . async ;
634
672
return new Promise . ES6 ( function ( resolve ) {
635
- if ( ! _this . _model . collection . buffer ) {
673
+ if ( ! collection . buffer ) {
636
674
process . nextTick ( function ( ) {
637
- var cursor = _this . _model . collection .
638
- aggregate ( _this . _pipeline , options || { } ) ;
675
+ var cursor = collection . aggregate ( pipeline , options ) ;
639
676
decorateCursor ( cursor ) ;
640
677
resolve ( cursor ) ;
641
678
callback && callback ( null , cursor ) ;
642
679
} ) ;
643
680
return ;
644
681
}
645
- _this . _model . collection . emitter . once ( 'queue' , function ( ) {
646
- var cursor = _this . _model . collection .
647
- aggregate ( _this . _pipeline , options || { } ) ;
682
+ collection . emitter . once ( 'queue' , function ( ) {
683
+ var cursor = collection . aggregate ( pipeline , options ) ;
648
684
decorateCursor ( cursor ) ;
649
685
resolve ( cursor ) ;
650
686
callback && callback ( null , cursor ) ;
@@ -654,14 +690,13 @@ Aggregate.prototype.exec = function(callback) {
654
690
delete options . cursor . useMongooseAggCursor ;
655
691
return new AggregationCursor ( this ) ;
656
692
}
657
- var cursor = this . _model . collection .
658
- aggregate ( this . _pipeline , this . options || { } ) ;
693
+ var cursor = collection . aggregate ( pipeline , options ) ;
659
694
decorateCursor ( cursor ) ;
660
695
return cursor ;
661
696
}
662
697
663
698
return new Promise . ES6 ( function ( resolve , reject ) {
664
- if ( ! _this . _pipeline . length ) {
699
+ if ( ! pipeline . length ) {
665
700
var err = new Error ( 'Aggregate has empty pipeline' ) ;
666
701
if ( callback ) {
667
702
callback ( err ) ;
@@ -672,9 +707,20 @@ Aggregate.prototype.exec = function(callback) {
672
707
673
708
prepareDiscriminatorPipeline ( _this ) ;
674
709
675
- _this . _model
676
- . collection
677
- . aggregate ( _this . _pipeline , _this . options || { } , function ( error , result ) {
710
+ model . hooks . execPre ( 'aggregate' , _this , function ( error ) {
711
+ if ( error ) {
712
+ var _opts = { error : error } ;
713
+ return model . hooks . execPost ( 'aggregate' , _this , [ null ] , _opts , function ( error ) {
714
+ if ( callback ) {
715
+ callback ( error ) ;
716
+ }
717
+ reject ( error ) ;
718
+ } ) ;
719
+ }
720
+
721
+ collection . aggregate ( pipeline , options , function ( error , result ) {
722
+ var _opts = { error : error } ;
723
+ model . hooks . execPost ( 'aggregate' , _this , [ result ] , _opts , function ( error , result ) {
678
724
if ( error ) {
679
725
if ( callback ) {
680
726
callback ( error ) ;
@@ -688,6 +734,8 @@ Aggregate.prototype.exec = function(callback) {
688
734
}
689
735
resolve ( result ) ;
690
736
} ) ;
737
+ } ) ;
738
+ } ) ;
691
739
} ) ;
692
740
} ;
693
741
@@ -758,6 +806,8 @@ function isOperator(obj) {
758
806
* @param {Aggregate } aggregate Aggregate to prepare
759
807
*/
760
808
809
+ Aggregate . _prepareDiscriminatorPipeline = prepareDiscriminatorPipeline ;
810
+
761
811
function prepareDiscriminatorPipeline ( aggregate ) {
762
812
var schema = aggregate . _model . schema ,
763
813
discriminatorMapping = schema && schema . discriminatorMapping ;
@@ -781,12 +831,11 @@ function prepareDiscriminatorPipeline(aggregate) {
781
831
} else {
782
832
var match = { } ;
783
833
match [ discriminatorKey ] = discriminatorValue ;
784
- aggregate . _pipeline = [ { $match : match } ] . concat ( originalPipeline ) ;
834
+ aggregate . _pipeline . unshift ( { $match : match } ) ;
785
835
}
786
836
}
787
837
}
788
838
789
-
790
839
/*!
791
840
* Exports
792
841
*/
0 commit comments