skip to content
Alvin Lucillo

Conditional projection

/ 2 min read

You can use conditions to specify what to output in projected documents. Similar to yesterday’s entry, the pipeline selects specific text via a capture group and picks the first occurrence. Unlike yesterday’s regex, capture group is specific to the first digit after the closing parenthesis. In the second stage, the first element is assigned to network_digit. Finally, the last stage uses $cond, which accepts the condition $eq, true value, and false value. The true value is pldt, while the false value performs another conditional expression.

// test data
// persons data with Philippine landline format:
// (area code) network + local number, e.g. (02) 8123-4567
db.getCollection("persons").insertMany([
	{ name: "Person1", contact_number: "(02) 8123-4567" },
	{ name: "Person2", contact_number: "(02) 8234-5678" },
	{ name: "Person3", contact_number: "(032) 7345-6789" },
	{ name: "Person4", contact_number: "(032) 7456-7890" },
	{ name: "Person5", contact_number: "(082) 8567-8901" },
	{ name: "Person6", contact_number: "(082) 8678-9012" },
	{ name: "Person7", contact_number: "(082) 5567-8901" },
	{ name: "Person8", contact_number: "(082) 5678-9012" },
]);

// Count people per network group:
// 8 -> pldt, 7 -> globe, else -> others
db.getCollection("persons").aggregate([
	{
		$project: {
			match: { $regexFind: { input: "$contact_number", regex: /^\(\d+\)\s*(\d)/ } },
		},
	},
	{
		$project: {
			network_digit: { $arrayElemAt: ["$match.captures", 0] },
		},
	},
	{
		$project: {
			network: {
				$cond: [
					{ $eq: ["$network_digit", "8"] },
					"pldt",
					{
						$cond: [{ $eq: ["$network_digit", "7"] }, "globe", "others"],
					},
				],
			},
		},
	},
	{
		$group: {
			_id: "$network",
			people_count: { $sum: 1 },
		},
	},
	{ $sort: { _id: 1 } },
]);

Output:

[
	{
		"_id": "globe",
		"people_count": 2
	},
	{
		"_id": "others",
		"people_count": 2
	},
	{
		"_id": "pldt",
		"people_count": 4
	}
]