* BsonUnwindElement produces the output document when element * at the unwind target * document -> source document * path -> path being unwound * indexFieldName -> optional name for the index field to be added * element -> the value found at the unwind target */
| 395 | * element -> the value found at the unwind target |
| 396 | */ |
| 397 | static pgbson * |
| 398 | BsonUnwindElement(pgbson *document, char *path, char *indexFieldName, long index, const |
| 399 | bson_value_t *element) |
| 400 | { |
| 401 | /* |
| 402 | * Document: { "a" : [ 1, [1,2], { "c": "value"}, "x"] } |
| 403 | * Unwind Spec: { "$unwind" : "a" } |
| 404 | * |
| 405 | * Expected Result: { "a" : 1} |
| 406 | * { "a" : [1,2] } |
| 407 | * { "a" : { "c": "value"} } |
| 408 | * { "a" : "x" } |
| 409 | * |
| 410 | * This is achieved by performing AddFields() 4 times on the original source document |
| 411 | * using the following 4 AddFields spec. Basically, we replace the array path with the |
| 412 | * elements of the array. |
| 413 | * 1. {"addFields" : { "a" : 1}} |
| 414 | * 2. {"addFields" : { "a" : [1,2] }} |
| 415 | * 3. {"addFields" : { "a" : { "c": "value"} }} |
| 416 | * 4. {"addFields" : { "a" : "x" }} |
| 417 | * |
| 418 | * We also, instruct the addFields spec to treat the elemnts to be the final value without |
| 419 | * any need for recursive expression evaluation. |
| 420 | * |
| 421 | * Note: All other fields in the document (not shown here) gets projected as it is. |
| 422 | * |
| 423 | */ |
| 424 | |
| 425 | BsonIntermediatePathNode *root = MakeRootNode(); |
| 426 | |
| 427 | /* unwound elements come from arrays in documents which will already be evaluated in a previous stage or directly from a collection, */ |
| 428 | /* so we can safely treat the values as constants and no need to pay the cost to parse them as expressions. */ |
| 429 | bool treatLeafDataAsConstant = true; |
| 430 | ParseAggregationExpressionContext parseContext = { 0 }; |
| 431 | |
| 432 | /* Create the node for unwound element */ |
| 433 | if (element->value_type != BSON_TYPE_EOD) |
| 434 | { |
| 435 | StringView pathView = CreateStringViewFromString(path); |
| 436 | TraverseDottedPathAndAddLeafFieldNode(&pathView, |
| 437 | element, |
| 438 | root, |
| 439 | BsonDefaultCreateLeafNode, |
| 440 | treatLeafDataAsConstant, |
| 441 | &parseContext); |
| 442 | } |
| 443 | |
| 444 | /* Create the node for the new indexField name */ |
| 445 | if (indexFieldName != NULL) |
| 446 | { |
| 447 | bson_value_t indexValue; |
| 448 | memset(&indexValue, 0, sizeof(bson_value_t)); |
| 449 | if (index > -1) |
| 450 | { |
| 451 | indexValue.value_type = BSON_TYPE_INT64; |
| 452 | indexValue.value.v_int64 = index; |
| 453 | } |
| 454 | else |
no test coverage detected