|
35 | 35 | user_fun, |
36 | 36 | user_acc, |
37 | 37 | fields, |
38 | | - execution_stats |
| 38 | + execution_stats, |
| 39 | + documents_seen |
39 | 40 | }). |
40 | 41 |
|
41 | 42 | create(Db, {Indexes, Trace}, Selector, Opts) -> |
@@ -103,7 +104,8 @@ execute(Cursor, UserFun, UserAcc) -> |
103 | 104 | user_fun = UserFun, |
104 | 105 | user_acc = UserAcc, |
105 | 106 | fields = Cursor#cursor.fields, |
106 | | - execution_stats = mango_execution_stats:log_start(Stats) |
| 107 | + execution_stats = mango_execution_stats:log_start(Stats), |
| 108 | + documents_seen = sets:new([{version, 2}]) |
107 | 109 | }, |
108 | 110 | try |
109 | 111 | case Query of |
@@ -171,26 +173,39 @@ handle_hit(CAcc0, Hit, Doc) -> |
171 | 173 | #cacc{ |
172 | 174 | limit = Limit, |
173 | 175 | skip = Skip, |
174 | | - execution_stats = Stats |
| 176 | + execution_stats = Stats, |
| 177 | + documents_seen = Seen |
175 | 178 | } = CAcc0, |
176 | 179 | CAcc1 = update_bookmark(CAcc0, Hit), |
177 | 180 | Stats1 = mango_execution_stats:incr_docs_examined(Stats), |
178 | 181 | couch_stats:increment_counter([mango, docs_examined]), |
179 | 182 | CAcc2 = CAcc1#cacc{execution_stats = Stats1}, |
180 | 183 | case mango_selector:match(CAcc2#cacc.selector, Doc) of |
181 | | - true when Skip > 0 -> |
182 | | - CAcc2#cacc{skip = Skip - 1}; |
183 | | - true when Limit == 0 -> |
184 | | - % We hit this case if the user spcified with a |
185 | | - % zero limit. Notice that in this case we need |
186 | | - % to return the bookmark from before this match |
187 | | - throw({stop, CAcc0}); |
188 | | - true when Limit == 1 -> |
189 | | - NewCAcc = apply_user_fun(CAcc2, Doc), |
190 | | - throw({stop, NewCAcc}); |
191 | | - true when Limit > 1 -> |
192 | | - NewCAcc = apply_user_fun(CAcc2, Doc), |
193 | | - NewCAcc#cacc{limit = Limit - 1}; |
| 184 | + true -> |
| 185 | + DocId = mango_fields:extract(Doc, [<<"_id">>]), |
| 186 | + case sets:is_element(DocId, Seen) of |
| 187 | + true -> |
| 188 | + CAcc2; |
| 189 | + false -> |
| 190 | + CAcc3 = CAcc2#cacc{ |
| 191 | + documents_seen = sets:add_element(DocId, Seen) |
| 192 | + }, |
| 193 | + if |
| 194 | + Skip > 0 -> |
| 195 | + CAcc3#cacc{skip = Skip - 1}; |
| 196 | + Limit == 0 -> |
| 197 | + % We hit this case if the user specified with a |
| 198 | + % zero limit. Notice that in this case we need |
| 199 | + % to return the bookmark from before this match. |
| 200 | + throw({stop, CAcc0}); |
| 201 | + Limit == 1 -> |
| 202 | + CAcc4 = apply_user_fun(CAcc3, Doc), |
| 203 | + throw({stop, CAcc4}); |
| 204 | + Limit > 1 -> |
| 205 | + CAcc4 = apply_user_fun(CAcc3, Doc), |
| 206 | + CAcc4#cacc{limit = Limit - 1} |
| 207 | + end |
| 208 | + end; |
194 | 209 | false -> |
195 | 210 | CAcc2 |
196 | 211 | end. |
|
0 commit comments