MongoDB聚合框架:计算数组元素权重并跳过末尾连续C元素
Fixing MongoDB Aggregation to Handle Trailing Consecutive "C" Values
Got it, let's get your aggregation logic sorted to properly handle those trailing consecutive "C" elements. The core issue with your original code is that it only accounts for a single trailing "C"—we need to first identify how many consecutive "C"s are at the end of the array, then target the last non-"C" element correctly.
First, Let's Recap Your Weight Rules
- If the last element isn't "C": Assign weight
1.0to the final element,0to all others - If the last element is "C": Skip all consecutive trailing "C"s, assign weight
1to the last non-"C" element,0to everything else - If the array has only 1 element: Assign weight
1to that element
Corrected Aggregation Code
db.col.aggregate([ { $addFields: { // Extract just the values from myArray to simplify processing valueArray: { $map: { input: "$myArray", as: "elem", in: "$$elem.value" } }, // Reverse the value array to find trailing Cs from the start reversedValues: { $reverseArray: "$valueArray" } } }, { $addFields: { // Find the index of the first non-C in the reversed array (this is the count of trailing Cs) trailingCCount: { $indexOfArray: [ "$reversedValues", { $not: { $eq: "C" } } ] }, // Handle edge case: if all elements are C, trailingCCount will be -1, so set to array length adjustedTrailingCCount: { $cond: [ { $eq: ["$trailingCCount", -1] }, { $size: "$valueArray" }, "$trailingCCount" ] } } }, { $addFields: { // Calculate the index of the last non-C element in the original array targetIndex: { $subtract: [ { $size: "$myArray" }, "$adjustedTrailingCCount", 1 ] } } }, { $addFields: { // Build the final weighted array myArray: { $map: { input: "$myArray", as: "elem", in: { value: "$$elem.value", weight: { $cond: [ { $eq: [{ $indexOfArray: ["$myArray", "$$elem"] }, "$targetIndex"] }, 1, 0 ] } } } } } }, // Clean up the temporary fields we created { $project: { valueArray: 0, reversedValues: 0, trailingCCount: 0, adjustedTrailingCCount: 0, targetIndex: 0 } } ])
How This Works
Let's walk through the logic with your sample documents:
For Document 1 (myArray: [C, A, C, B, A, A])
valueArraybecomes["C", "A", "C", "B", "A", "A"]reversedValuesis["A", "A", "B", "C", "A", "C"]trailingCCountis0(first element in reversed array is non-C)targetIndexis6 - 0 - 1 = 5(the last element in the original array)- The
$mapassigns weight1to index 5,0to others—matches your expected result.
For Document 2 (myArray: [A, C, B, C, C])
valueArraybecomes["A", "C", "B", "C", "C"]reversedValuesis["C", "C", "B", "C", "A"]trailingCCountis2(first non-C is at index 2 in reversed array)targetIndexis5 - 2 - 1 = 2(the "B" element in original array)- The
$mapassigns weight1to index 2,0to others—perfect match for your expected result.
Edge Case: All Elements Are C (myArray: [C, C, C])
If every element is "C", the code will set adjustedTrailingCCount to the array length, resulting in targetIndex being -1. The $map will assign 0 to all elements—this is a reasonable default since there's no non-C element to apply the weight rule to.
内容的提问来源于stack exchange,提问作者Dr. Mza
相关产品推荐
相关产品推荐

