# Actionable Data With MongoDB and Go

- Published: June 25, 2014
- Author: William Kennedy
- URL: https://www.ardanlabs.com/blog/2014/06/actionable-data-with-mongodb-and-go.html

<span style="font-size: large;">Introduction</span><br />
If you are building any kind of application for a consumer based product, it is common to have large amounts of application data being generated about your users. Running reports is a traditional use of this data, but what if you could make this data actionable? What if you could adapt the user experience by aggregating and testing this data against rules that could dictate actions or special messaging?<br />
<br />
In this post I am going to show you a way that could be used to make your application data &quot;actionable&quot;. We are going to review a sample program written in Go that leverages MongoDB's aggregation pipeline to execute rules that aggregate and test data. The rule the program defines and executes determines what messaging we want to show the user based on their current set of financial transactions in the system.<br />
<br />
<span style="font-size: large;">The Data</span><br />
We have two collections of data we will be using which are being hosted in a public [MongoLab](/broken-link) database.&nbsp;The first collection contains credit card transactions for users. This data represent application generated data:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
Collection: demo_user_transactions<br />
{<br />
&nbsp; &nbsp; &quot;user_id&quot; : &quot;396bc782-6ac6-4183-a671-6e75ca5989a5&quot;,<br />
&nbsp; &nbsp; &quot;description&quot; : &quot;Chevron&quot;,<br />
&nbsp; &nbsp; &quot;amount&quot; : 23.76,<br />
&nbsp; &nbsp; &quot;date&quot; : ISODate(&quot;2014-04-20T00:00:00.000Z&quot;),<br />
&nbsp; &nbsp; &quot;category&quot; : &quot;gas&quot;<br />
},<br />
{<br />
&nbsp; &nbsp; &quot;user_id&quot; : &quot;396bc782-6ac6-4183-a671-6e75ca5989a5&quot;,<br />
&nbsp; &nbsp; &quot;description&quot; : &quot;Fandango&quot;,<br />
&nbsp; &nbsp; &quot;amount&quot; : 15.6,<br />
&nbsp; &nbsp; &quot;date&quot; : ISODate(&quot;2014-04-20T00:00:00.000Z&quot;),<br />
&nbsp; &nbsp; &quot;category&quot; : &quot;movies&quot;<br />
}</div>
<br />
The second collection contains a set of user advice which is presented to the user based on some aspect of their financial transactions. This data represents configuration data:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
Collection: demo_user_advice<br />
{<br />
&nbsp; &nbsp; &quot;advice_id&quot; : 1,<br />
&nbsp; &nbsp; &quot;title&quot; : &quot;Dealing with Rising Gas Prices&quot;,<br />
&nbsp; &nbsp; &quot;link&quot; : &quot;www.careonecredit.com/knowledge/dealingwithrisinggasprices.aspx&quot;,<br />
&nbsp; &nbsp; &quot;desc&quot; : &quot;With gas prices rising, and no relief in sight, looking for...&quot;<br />
},<br />
{<br />
&nbsp; &nbsp; &quot;advice_id&quot; : 2,<br />
&nbsp; &nbsp; &quot;title&quot; : &quot;Ways To Stretch A Dollar&quot;,<br />
&nbsp; &nbsp; &quot;link&quot; : &quot;www.careonecredit.com/knowledge/ways-to-stretch-a-dollar.aspx&quot;,<br />
&nbsp; &nbsp; &quot;desc&quot; : &quot;Are you looking for ways to make your dollar go further?...&quot;<br />
}</div>
<br />
We can imagine the transaction data is changing as the system refreshes user transactions throughout the day. The advice data is configurable and can be changed by marketing or business analyst people throughout the day as well. These two collections will allow us to create rules and adapt the user experience by providing the most relevant advice for the target user.<br />
<br />
<span style="font-size: large;">The Rule</span><br />
To make the data actionable we need to define a rule. For this sample program, a rule defines a test expression that is run through the aggregation pipeline to determine a <span style="font-family: Courier New, Courier, monospace;">true</span> or <span style="font-family: Courier New, Courier, monospace;">false</span> condition which then results in an action. For this example we are going to create a rule that looks at a user’s purchasing of gasoline. Based on the amount of money the user spends, the action will be to display a piece of advice that is relevant.<br />
<br />
Let’s look at the rule we are going to run and the success and failure actions:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
{<br />
&nbsp; &quot;test&quot; : {<br />
&nbsp; &nbsp; &quot;collection&quot; : &quot;demo_user_transactions&quot;,<br />
&nbsp; &nbsp; &nbsp; &quot;expressions&quot; : [<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;{ \&quot;$match\&quot; : { \&quot;user_id\&quot; : \&quot;#userId#\&quot;, \&quot;category\&quot; : \&quot;gas\&quot; }}&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;{ \&quot;$group\&quot; : { \&quot;_id\&quot; : { \&quot;category\&quot; : \&quot;$category\&quot; }, \&quot;amount\&quot; : { \&quot;$sum\&quot; : \&quot;$amount\&quot; }}}&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;{ \&quot;$match\&quot; : { \&quot;amount\&quot; : { \&quot;$gt\&quot; : 20.00}}}&quot;<br />
&nbsp; &nbsp; &nbsp; ]<br />
&nbsp; },<br />
&nbsp; &quot;success&quot; : {<br />
&nbsp; &nbsp; &nbsp; &quot;collection&quot; : &quot;demo_advice&quot;,<br />
&nbsp; &nbsp; &nbsp; &quot;expressions&quot; : [<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;{ \&quot;$match\&quot; : { \&quot;advice_id\&quot; : 1 }}&quot;<br />
&nbsp; &nbsp; &nbsp; ]<br />
&nbsp; },<br />
&nbsp; &quot;failed&quot; : {<br />
&nbsp; &nbsp; &nbsp; &quot;collection&quot; : &quot;demo_advice&quot;,<br />
&nbsp; &nbsp; &nbsp; &quot;expressions&quot; : [<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;{ \&quot;$match\&quot; : { \&quot;advice_id\&quot; : 2 }}&quot;<br />
&nbsp; &nbsp; &nbsp; ]<br />
&nbsp; }<br />
}
</div>
<br />
The rule is defined as a JSON document that contains three fields each with a sub-document that contains a collection name and the set of expressions to be run through the aggregation pipeline. When the expressions for the <span style="font-family: Courier New, Courier, monospace;">test</span> field returns a dataset, then the application will run the expressions defined in the <span style="font-family: Courier New, Courier, monospace;">success</span> field. When no dataset is returned, then the application will run the expressions in the <span style="font-family: Courier New, Courier, monospace;">failed</span> field.<br />
<br />
If we look at the rule a bit closer we can see what we are testing:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
{ &quot;$match&quot; : { &quot;user_id&quot; : &quot;#userId#&quot;, &quot;category&quot; : &quot;gas&quot; }}<br />
{ &quot;$group&quot; : { &quot;_id&quot; : { &quot;category&quot; : &quot;$category&quot; }, &quot;amount&quot; : { &quot;$sum&quot; : &quot;$amount&quot; }}}<br />
{ &quot;$match&quot; : { &quot;amount&quot; : { &quot;$gt&quot; : 20.00}}}
</div>
<br />
The first pipeline operation uses a <span style="font-family: Courier New, Courier, monospace;">$match</span> command to find all the documents from the <span style="font-family: Courier New, Courier, monospace;">demo_user_transactions</span> collection for a specific user where the category is <span style="font-family: Courier New, Courier, monospace;">gas</span>. The <span style="font-family: Courier New, Courier, monospace;">#userId#</span> tag is replaced with the actual user id by the program before running the expression. Then those <span style="font-family: Courier New, Courier, monospace;">gas</span> transactions are grouped and the total amount spent on gasoline is calculated using the <span style="font-family: Courier New, Courier, monospace;">$group</span> command. Finally that total spend on gasoline is tested to see if it is greater than $20. If the total spend on gasoline is greater than $20, there will be a dataset returned signifying the rule is <span style="font-family: Courier New, Courier, monospace;">true</span> else no dataset is returned and the rule is <span style="font-family: Courier New, Courier, monospace;">false</span>.<br />
<br />
<span style="font-size: large;">The Code</span><br />
Now that we have a brief understanding of the data and the rule, we can examine some of the code that executes this rule against our test MongoDB database. The code is in <a href="https://github.com/goinggo/mgoaction" target="_blank">Github</a> and you can use the following Go command if you have Go already installed:
<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
go get github.com/goinggo/mgoaction
</div>
<br />
If you don't have Go installed check out these links to get started:<br />
<br />
<a href="http://golang.org/doc/install" target="_blank"><span class="sr-only">External resource on golang.org: </span>http&#58;//golang.org/doc/install</a><br />
<a href="https://www.ardanlabs.com/blog/2013/06/installing-go-gocode-gdb-and-liteide.html" target="_blank"><span class="sr-only">External resource on ardanlabs.com: </span>https&#58;//www.ardanlabs.com/blog/2013/06/installing-go-gocode-gdb-and-liteide.html</a><br />
<br />
To make the application dynamic and keep things simple, the rule is being kept in an individual JSON file within a project folder called <span style="font-family: Courier New, Courier, monospace;">rules</span>. This allows us to change the rule without needing to change the program. Let’s examine the function that reads and decode the JSON document from within a given file into a Go struct value so the rule can be processed by the program. We have already seen the JSON document for the rule above, so here are the structs that the JSON document will be decoded into:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
// operation contains a set of expressions for a collection.<br />
type operation struct {<br />
&nbsp; &nbsp; Collection &nbsp;string &nbsp; `json:&quot;collection&quot;`<br />
&nbsp; &nbsp; Expressions []string `json:&quot;expressions&quot;`<br />
}<br />
<br />
// rule contains a single rule with an action.<br />
type rule struct {<br />
&nbsp; &nbsp; Test &nbsp; &nbsp;operation `json:&quot;rule&quot;`<br />
&nbsp; &nbsp; Success operation `json:&quot;success&quot;`<br />
&nbsp; &nbsp; Failed &nbsp;operation `json:&quot;failed&quot;`<br />
}</div>
<br />
Support for decoding JSON documents exists within the Go standard library. Here is the function <span style="font-family: Courier New, Courier, monospace;">retrieveRule</span> that decodes the JSON document found in&nbsp;<span style="font-family: Courier New, Courier, monospace;">rules/advice.json</span>&nbsp;into a value of type <span style="font-family: Courier New, Courier, monospace;">rule</span><span style="font-family: Arial, Helvetica, sans-serif;">:</span><br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
&nbsp;92 // retrieveRule reads and unmarshals the specified rule data file.<br />
&nbsp;93 func retrieveRule(ruleName string) (&#42;rule, error) {<br />
&nbsp;94 &nbsp; &nbsp; // Open the file.<br />
&nbsp;95 &nbsp; &nbsp; file, err := os.Open(&quot;rules/&quot; + ruleName + &quot;.json&quot;)<br />
&nbsp;96 &nbsp; &nbsp; if err != nil {<br />
&nbsp;97 &nbsp; &nbsp; &nbsp; &nbsp; return nil, err<br />
&nbsp;98 &nbsp; &nbsp; }<br />
&nbsp;99<br />
100 &nbsp; &nbsp; // Schedule the file to be closed once the function returns.<br />
101 &nbsp; &nbsp; defer file.Close()<br />
102<br />
103 &nbsp; &nbsp; // Decode the file into a value of the rule type.<br />
104 &nbsp; &nbsp; var r rule<br />
105 &nbsp; &nbsp; err = json.NewDecoder(file).Decode(&amp;r)<br />
106<br />
107 &nbsp; &nbsp; // We don't need to check for errors, the caller can do this.<br />
108 &nbsp; &nbsp; return &amp;r, err<br />
109 }
</div>
<br />
The function is passed a rule name which is used to form the path to the rule file. On line 95 the file is opened and then on line 104 a variable named <span style="font-family: Courier New, Courier, monospace;">r</span> of type <span style="font-family: Courier New, Courier, monospace;">rule</span> is declared. In combination with the <span style="font-family: Courier New, Courier, monospace;">json</span> package's&nbsp;<span style="font-family: Courier New, Courier, monospace;">NewDecoder</span> function followed by the <span style="font-family: Courier New, Courier, monospace;">Decode</span> method on line 105, the value of the <span style="font-family: Courier New, Courier, monospace;">r</span> variable is updated to reflect the JSON document’s data. Then the address of the variable is passed out of the function for use on line 108.<br />
<br />
Next let’s look at the rule processing function named <span style="font-family: Courier New, Courier, monospace;">processRule</span>:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
111 // processRule processes the rule and displays the results.<br />
112 func processRule(session &#42;mgo.Session, r &#42;rule, user string) error {<br />
113 &nbsp; &nbsp; // Process the rule and check for results<br />
114 &nbsp; &nbsp; log.Println(&quot;Test:&quot;)<br />
115 &nbsp; &nbsp; results, err := executeOperation(session, r.Test, user)<br />
116 &nbsp; &nbsp; if err != nil {<br />
117 &nbsp; &nbsp; &nbsp; &nbsp; log.Println(&quot;Unable To Process Action&quot;, err)<br />
118 &nbsp; &nbsp; &nbsp; &nbsp; return err<br />
119 &nbsp; &nbsp; }<br />
120<br />
121 &nbsp; &nbsp; if len(results) == 0 {<br />
122 &nbsp; &nbsp; &nbsp; &nbsp; // If no result is returned, provide the failed result<br />
123 &nbsp; &nbsp; &nbsp; &nbsp; log.Println(&quot;Failed:&quot;)<br />
124 &nbsp; &nbsp; &nbsp; &nbsp; _, err = executeOperation(session, r.Failed, user)<br />
125 &nbsp; &nbsp; } else {<br />
126 &nbsp; &nbsp; &nbsp; &nbsp; // Provide the success result<br />
127 &nbsp; &nbsp; &nbsp; &nbsp; log.Println(&quot;Succeeded:&quot;)<br />
128 &nbsp; &nbsp; &nbsp; &nbsp; _, err = executeOperation(session, r.Success, user)<br />
129 &nbsp; &nbsp; }<br />
130<br />
131 &nbsp; &nbsp; if err != nil {<br />
132 &nbsp; &nbsp; &nbsp; &nbsp; log.Println(&quot;Unable To Process Action&quot;, err)<br />
133 &nbsp; &nbsp; }<br />
134<br />
135 &nbsp; &nbsp; return err<br />
136 }
</div>
<br />
This function on line 115 executes the expressions for the <span style="font-family: Courier New, Courier, monospace;">Test</span> field using the aggregation pipeline and then on line 116 checks for errors. If there are no errors, the determination if a result was returned is tested on line 121. If there is no result, the function executes the set of expressions for the <span style="font-family: Courier New, Courier, monospace;">Failed</span> field on line 124, else the <span style="font-family: Courier New, Courier, monospace;">Success</span> field expressions are executed on line 128. A test for an error value occurs one more time on line 131 for logging purposes and then the function returns.<br />
<br />
Let’s look at one more function named <span style="font-family: Courier New, Courier, monospace;">executeOperation</span> to see how the expressions are actually sent to the aggregation pipeline for processing:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
138 // executeOperation builds an aggregation pipeline query based on the<br />
139 // configured expressions for the operation.<br />
140 func executeOperation(session &#42;mgo.Session, op operation, user string) ([]bson.M, error) {<br />
141 &nbsp; &nbsp; var err error<br />
142 &nbsp; &nbsp; expressions := make([]bson.M, len(op.Expressions))<br />
143<br />
144 &nbsp; &nbsp; // Iterate through the set of expressions and build the slice<br />
145 &nbsp; &nbsp; // of operations.<br />
146 &nbsp; &nbsp; for index, exp := range op.Expressions {<br />
147 &nbsp; &nbsp; &nbsp; &nbsp; if index := strings.Index(exp, &quot;#userId#&quot;); index &gt;= 0 {<br />
148 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exp = strings.Replace(exp, &quot;#userId#&quot;, user, -1)<br />
149 &nbsp; &nbsp; &nbsp; &nbsp; }<br />
150<br />
151 &nbsp; &nbsp; &nbsp; &nbsp; log.Println(exp)<br />
152 &nbsp; &nbsp; &nbsp; &nbsp; expressions[index] = decodeExpression(exp)<br />
153 &nbsp; &nbsp; }<br />
154<br />
155 &nbsp; &nbsp; // Capture a collection so we can execute the expressions.<br />
156 &nbsp; &nbsp; collection := session.DB(TestDatabase).C(op.Collection)<br />
157 &nbsp; &nbsp; if collection == nil {<br />
158 &nbsp; &nbsp; &nbsp; &nbsp; return nil, fmt.Errorf(&quot;Collection %s does not exist&quot;, op.Collection)<br />
159 &nbsp; &nbsp; }<br />
160<br />
161 &nbsp; &nbsp; // Execute the expressions against the aggregation pipeline.<br />
162 &nbsp; &nbsp; var results []bson.M<br />
163 &nbsp; &nbsp; err = collection.Pipe(expressions).All(&amp;results)<br />
164<br />
165 &nbsp; &nbsp; // Pretty print the result.<br />
166 &nbsp; &nbsp; output, _ := json.MarshalIndent(results, &quot;&quot;, &quot;    &quot;)<br />
167 &nbsp; &nbsp; log.Println(string(output))<br />
168<br />
169 &nbsp; &nbsp; return results, err<br />
170 }
</div>
<br />
On line 142 we declare a slice of type <span style="font-family: Courier New, Courier, monospace;">bson.M</span> named <span style="font-family: Courier New, Courier, monospace;">expressions</span> to hold all the expressions we need to execute and then between lines 146 through 153 we iterate through that set of expressions. The first thing that is done in each iteration on line 147 is to check the expression for a user id tag. If the tag is found, it is replaced with the actual user id. On line 151 the expression is displayed and finally on line 152 the expression is decoded into a map of type <span style="font-family: Courier New, Courier, monospace;">bson.M</span> and assigned to the <span style="font-family: Courier New, Courier, monospace;">expressions</span> slice.<br />
<br />
Once the slice of expressions is ready for execution, we capture a <span style="font-family: Courier New, Courier, monospace;">collection</span> value from the <span style="font-family: Courier New, Courier, monospace;">session</span>&nbsp;value on line 156 and execute the expressions against that collection on line 163. The results from the aggregation pipeline are then returned from the function for processing, which take the form of another map of type <span style="font-family: Courier New, Courier, monospace;">bson.M</span>. One line 166 we create a pretty print view of the results and then display those results on line 167.<br />
<br />
Now that we have seen the code, let’s look at the results when we run the program for the data and the rule we reviewed.<br />
<br />
<span style="font-size: large;">The Result</span><br />
When we run the program we see the following output:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
Test:<br />
{ &quot;$match&quot; : { &quot;user_id&quot; : &quot;396bc782-6ac6-4183-a671-6e75ca5989a5&quot;, &quot;category&quot; : &quot;gas&quot; }}<br />
{ &quot;$group&quot; : { &quot;_id&quot; : { &quot;category&quot; : &quot;$category&quot; }, &quot;amount&quot; : { &quot;$sum&quot; : &quot;$amount&quot; }}}<br />
{ &quot;$match&quot; : { &quot;amount&quot; : { &quot;$gt&quot; : 20.00}}}<br />
[<br />
&nbsp; {<br />
&nbsp; &nbsp; &quot;_id&quot;: {<br />
&nbsp; &nbsp; &nbsp; &quot;category&quot;: &quot;gas&quot;<br />
&nbsp; &nbsp; },<br />
&nbsp; &nbsp; &quot;amount&quot;: 23.76<br />
&nbsp; }<br />
]<br />
Success:<br />
{ &quot;$match&quot; : { &quot;advice_id&quot; : 1 }}<br />
[<br />
&nbsp; {<br />
&nbsp; &nbsp; &quot;_id&quot;: &quot;53a70e71792ac1bbba4b016e&quot;,<br />
&nbsp; &nbsp; &quot;advice_id&quot;: 1,<br />
&nbsp; &nbsp; &quot;desc&quot;: &quot;With gas prices rising, and no relief in sight, looking for...&quot;,<br />
&nbsp; &nbsp; &quot;link&quot;: &quot;www.careonecredit.com/knowledge/dealingwithrisinggasprices.aspx&quot;,<br />
&nbsp; &nbsp; &quot;title&quot;: &quot;Dealing with Rising Gas Prices&quot;<br />
&nbsp; }<br />
]
</div>
<br />
The first section of the output shows the <span style="font-family: Courier New, Courier, monospace;">Test</span> expressions that are executed through the aggregation pipeline with the result immediately following. The results show the total spend for the user was $23.76. Since this value is greater than $20.00, the code then proceeds to execute the Success expressions. This one expression returns the advice document for&nbsp;the advice about managing transportation costs.<br />
<br />
If we change the rule so it fails we should get the other piece of advice:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
Test:<br />
{ &quot;$match&quot; : { &quot;user_id&quot; : &quot;396bc782-6ac6-4183-a671-6e75ca5989a5&quot;, &quot;category&quot; : &quot;gas&quot; }}<br />
{ &quot;$group&quot; : { &quot;_id&quot; : { &quot;category&quot; : &quot;$category&quot; }, &quot;amount&quot; : { &quot;$sum&quot; : &quot;$amount&quot; }}}<br />
<b>{ &quot;$match&quot; : { &quot;amount&quot; : { &quot;$lt&quot; : 20.00}}}</b><br />
null<br />
Failed:<br />
{ &quot;$match&quot; : { &quot;advice_id&quot; : 2 }}<br />
[<br />
&nbsp; {<br />
&nbsp; &nbsp; &quot;_id&quot;: &quot;53a70e8a792ac1bbba4b016f&quot;,<br />
&nbsp; &nbsp; &quot;advice_id&quot;: 2,<br />
&nbsp; &nbsp; &quot;desc&quot;: &quot;Are you looking for ways to make your dollar go further? ...&quot;,<br />
&nbsp; &nbsp; &quot;link&quot;: &quot;www.careonecredit.com/knowledge/ways-to-stretch-a-dollar.aspx&quot;,<br />
&nbsp; &nbsp; &quot;title&quot;: &quot;Ways To Stretch A Dollar&quot;<br />
&nbsp; }<br />
]
</div>
<br />
This time we changed the rule to test for the total spend on gasoline to be less than $20.00. This change resulted in a <span style="font-family: Courier New, Courier, monospace;">null</span> dataset so the code proceeded to execute the <span style="font-family: Courier New, Courier, monospace;">Failed</span> expressions. This time the advice is more generalized around saving money.<br />
<br />
<span style="font-size: large;">Conclusion</span><br />
MongoDB with the aggregation pipeline allows you to design programs that can make your data actionable. This small Go program provides one way you can declare and process rules against data in your MongoDB collections and adapt your users experience. Using Go to drive your rules engine gives you the added benefit of high performance and concurrent processing. Together, MongoDB and Go can help you build these robust systems faster, smarter and with a ton of flexibility.
