Andrew Whitaker

QueryOver Series - Part 3: Selecting

In this post I’ll go over building the SELECT statement with NHibernate QueryOver. I’ll also cover the different ways you can actually get a result back from your query.

Selecting a single property

In the simplest case, you’ll want to select a single column from a single row. For example, if you wanted to retrieve a single Product’s Name:

1
2
3
4
string name = session.QueryOver<Product>()
    .Where(p => p.Id == 1)
    .Select(p => p.Name)
    .SingleOrDefault<string>();

Which yields the following SQL:

1
2
3
4
5
6
SELECT
    this_.Name as y0_
FROM
    Production.Product this_
WHERE
    this_.ProductID = 1;

Note that if your query actually returns more than one result, NHibernate will throw an exception, letting you know that the query did not return a unique result.

Similarly, if you want to select a list of single properties, say the Name of every Product:

1
2
3
IList<string> names = session.QueryOver<Product>()
    .Select(p => p.Name)
    .List<string>();

Generates:

1
2
3
4
SELECT
    this_.Name as y0_
FROM
    Production.Product this_

Selecting multiple properties

Most of the time you won’t want to select just one column, you’ll want to build a whole result set. You have a few options in this area:

Using SelectList

SelectList is one way to specify a list of properties you’d like to select. Here’s a simple example:

1
2
3
4
5
6
7
IList<object[]> productInformation = session.QueryOver<Product>()
    .SelectList(list => list
        .Select(p => p.Id)
        .Select(p => p.Name)
        .Select(p => p.StandardCost)
    )
    .List<object[]>();

This generates the SQL you’d expect:

1
2
3
4
5
6
SELECT
    this_.ProductID as y0_,
    this_.Name as y1_,
    this_.StandardCost as y2_
FROM
    Production.Product this_

Those are the basics of using SelectList. There are some cool things you can do with SelectList to build SELECT clauses dynamically.

SelectList accepts a QueryOverProjectionBuilder<TRoot>. We can take advantage of QueryOver’s dynamic nature to dynamically build a select list.

One way to do this is to create a method that accepts a QueryOverProjectionBuilder<TRoot> and has the same return type. To expand on the Product example above:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static QueryOverProjectionBuilder<Product> BuildSelectList(
    QueryOverProjectionBuilder<Product> list)
{
    bool getName = /* some condition */;

    if (getName)
    {
        list.Select(p => p.Name);
    }

    list
        .Select(p => p.Id)
        .Select(p => p.StandardCost);

    return list;
}

We can then call the method directly from SelectList:

1
2
3
IList<object[]> names = session.QueryOver<Product>()
    .SelectList(BuildSelectList)
    .List<object[]>();

Using Projections.ProjectionList()

Another way to build a SELECT clause is using Projections.ProjectionList(). You can pass a ProjectionList to the .Select method:

1
2
3
4
5
6
7
8
Product productAlias = null;

session.QueryOver<Product>(() => productAlias)
    .Select(Projections.ProjectionList()
        .Add(Projections.Property(() => productAlias.Id))
        .Add(Projections.Property(() => productAlias.Name))
    )
    .List<object[]>();

This generates the following SQL:

1
2
3
4
5
SELECT
    this_.ProductID as y0_,
    this_.Name as y1_
FROM
    Production.Product this_

It’s also easy to generate dynamic SELECT clauses with ProjectionList:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Product productAlias = null;

ProjectionList projectionList = Projections.ProjectionList()
    .Add(Projections.Property(() => productAlias.Id))
    .Add(Projections.Property(() => productAlias.StandardCost));

bool getName = true;

if (getName)
{
    projectionList.Add(Projections.Property(() => productAlias.Name));
}

session.QueryOver<Product>(() => productAlias)
    .Select(projectionList)
    .List<object[]>();

I think if you’re dynamically building the SELECT clause, Projections.ProjectionList is actually cleaner, due to the way you can easily build it outside of the query itself.

Aggregates

So far I’ve looked at building simple SELECTs. Now I’ll look at using aggregate functions.

In the simplest cases, using SelectList along with SelectGroup and the aggregate function you want will get the job done.

For example:

1
2
3
4
5
6
7
session.QueryOver<Product>()
    .JoinQueryOver(pr => pr.TransactionHistory, () => transactionHistoryAlias)
    .SelectList(list => list
        .SelectGroup(pr => pr.Id)
        .SelectCount(() => transactionHistoryAlias.Id)
    )
    .List<object[]>();

Will generate:

1
2
3
4
5
6
7
8
9
10
SELECT
    this_.ProductID as y0_,
    count(transactio1_.TransactionID) as y1_
FROM
    Production.Product this_
inner join
    Production.TransactionHistory transactio1_
        on this_.ProductID=transactio1_.ProductID
GROUP BY
    this_.ProductID

You can call SelectGroup multiple times to add more columns to group on. You’ll notice that .SelectGroup adds a column to the GROUP BY clause as well as the SELECT clause.

You can also add a HAVING clause, although it is not intuitive at all:

1
2
3
4
5
6
7
8
9
10
11
12
var results = session.QueryOver<Product>()
    .JoinQueryOver(pr => pr.TransactionHistory, () => transactionHistoryAlias)
    .SelectList(list => list
        .SelectGroup(pr => pr.Id)
        .SelectGroup(pr => pr.Name)
        .SelectCount(() => transactionHistoryAlias.Id)
    )
    /* Generates a HAVING clause: */
    .Where(Restrictions.Gt(
        Projections.Count(
            Projections.Property(() => transactionHistoryAlias.Id)), 5))
    .List<object[]>();

This generates the following SQL:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT
    this_.ProductID as y0_,
    this_.Name as y1_,
    count(transactio1_.TransactionID) as y2_
FROM
    Production.Product this_
inner join
    Production.TransactionHistory transactio1_
        on this_.ProductID=transactio1_.ProductID
GROUP BY
    this_.ProductID,
    this_.Name
HAVING
    count(transactio1_.TransactionID) > 5;

Subqueries

There are several ways to create subqueries. You can create a correlated subquery by creating an alias in the outer query and referencing it in the other query. Here’s an example using SelectList and SelectSubQuery:

1
2
3
4
5
6
7
8
9
10
11
12
13
var results = session.QueryOver<Product>(() => productAlias)
    .SelectList(list => list
        .Select(pr => pr.Id)
        .SelectSubQuery(
            QueryOver.Of<TransactionHistory>()
                // Creates a correlated subquery
                .Where(tx => tx.Product.Id == productAlias.Id)
                .OrderBy(tx => tx.TransactionDate).Asc
                .Select(tx => tx.TransactionDate)
                .Take(1)
            )
    )
    .List<object[]>();

Which generates:

1
2
3
4
5
6
7
8
9
10
11
12
SELECT
   this_.ProductID as y0_,
   (SELECT
       TOP (1)  this_0_.TransactionDate as y0_
   FROM
       Production.TransactionHistory this_0_
   WHERE
       this_0_.ProductID = this_.ProductID
   ORDER BY
       this_0_.TransactionDate asc) as y1_
FROM
   Production.Product this_;

In general, if you can’t find a method on QueryOverProjectionBuilder<TRoot> using .SelectList, you can drop back into criteria methods on the Projections class. For example, say you want to use a case statement in your SELECT clause. You can use Projections.Conditional for that:

1
2
3
4
5
6
7
8
9
10
11
var results = session.QueryOver<Product>(() => productAlias)
    .JoinQueryOver(pr => pr.TransactionHistory, () => transactionHistoryAlias)
    .SelectList(list => list
        .Select(pr => pr.Id)
        .Select(Projections.Conditional(
            Restrictions.Gt(
                Projections.Property(() => transactionHistoryAlias.Quantity), 5),
            Projections.Constant(true),
            Projections.Constant(false)
    )))
    .List<object[]>();

Which generates:

1
2
3
4
5
6
7
8
9
10
11
SELECT
    this_.ProductID as y0_,
    (case
        when transactio1_.Quantity > 5 then 'True'
        else 'False'
    end) as y1_
FROM
    Production.Product this_
inner join
    Production.TransactionHistory transactio1_
        on this_.ProductID=transactio1_.ProductID;

Summary

This post covered a lot, but that’s because there are many ways to build a SELECT clause with QueryOver. In summary:

  • Select can be used to build a SELECT clause with single columns
  • SelectList and Projections.ProjectionList can be used to create more complex SELECT clauses.
  • When aggregating values, use SelectGroup (or Projections.GroupProperty).
  • For more complex scenarios, you can drop back in to Criteria methods on the Projections class. These support lambda expressions and can be used with QueryOver.

QueryOver Series - Part 2: Basics and Joining

In this post, I’ll outline some basics on QueryOver, including the NHibernate types involved and basic query structure. I’ll also talk about joining using JoinAlias and JoinQueryOver

IQueryOver<TRoot, TSubType>

If you look closely at the types involved when writing QueryOver queries, you’ll notice that there are two generic type parameters: TRoot and TSubType. Why would the API need two type parameters?

When you create a QueryOver object using session.QueryOver<TRoot>, TRoot and TSubType are the same. TRoot stays the same as you build the query, and TSubType changes as you use JoinQueryOver to join to other tables. This is worth mentioning before we go into more depth on building queries.

In general:

  • Operations except for .Select use TSubType as the type parameter for lambda expressions you pass to QueryOver methods
  • TRoot is the type parameter for lambda expressions you use in the .Select step of the query.

Here’s an example:

1
2
3
4
5
6
7
8
session.QueryOver<Person>()
// TRoot and TSubType are Person                         
    .JoinQueryOver(p => p.Addresses)
    // TRoot is Person, TSubtype is Address
        .Where(a => a.ModifiedDate == DateTime.Now)
        // Where accepts an Expression<Func<TSubtype, bool>>
        .Select(p => p.Id);
        // Select accepts an Expression<Func<TRoot, object>>

JoinAlias and JoinQueryOver

Since we’re on the subject of TRoot and TSubType, now is a good opportunity to talk about JoinAlias and JoinQueryOver

JoinAlias

JoinAlias adds a join to your query without changing TSubType. This is useful if you’re joining to more than one table from a source table:

1
2
3
4
5
6
7
8
BusinessEntityAddress addressAlias = null;
BusinessEntityContact contactAlias = null;

session.QueryOver<Person>()
    .JoinAlias(p => p.Addresses, () => addressAlias)
    .JoinAlias(p => p.Contacts, () => contactAlias)
    .Where(p => p.FirstName == "Andrew")
    /* etc */

In this example, since we want to join to Address and Contact, we can use JoinAlias twice, since TSubType doesn’t change.

The second parameter (in this particular overload) to .JoinAlias is a lambda expression that creates an alias. You can use the alias throughout the query in other lambda expressions when you don’t want to use either TRoot or TSubType.

JoinQueryOver

JoinQueryOver adds a join to your query and changes TSubType. You can also use an alias with JoinQueryOver, but with simpler queries it’s often not necessary:

1
2
3
4
session.QueryOver<Person>()
    .JoinQueryOver(p => p.Addresses)
        .Where(a => a.ModifiedDate == DateTime.Now)
    .Select(p => p.FirstName)

Notice that the lambda expression passed to the .Where method has the signature Expression<Func<Address, bool>>. The call to JoinQueryOver changed TSubType. This can make for more concise, easier to read code, since you don’t need to declare aliases for every join you do.

JoinAlias and JoinQueryOver are interchangeable, as far as I know. You can write the same query using either one, it’s just that the number of aliases you declare changes based on which you use. Typically I choose whichever one avoids creating and managing more aliases. This means using JoinQueryOver when possible, but that’s personal preference.

Summary:

  • IQueryOver is a generic type with two type parameters TRoot and TSubType
  • .Select operates on TRoot while other QueryOver methods operate on TSubType.
  • TRoot stays the same as you’re building a query, but TSubType changes when you join using JoinQueryOver
  • JoinQueryOver and JoinAlias add joins to your query. JoinAlias doesn’t change TSubType, but JoinQueryOver does.
  • You can use aliases when building a query to refer to properties that don’t belong to TRoot or TSubType

QueryOver Series - Part 1: Why QueryOver?

QueryOver is a strongly-typed querying technology built on top of NHibernate’s Criteria API. It was introduced in NHibernate 3.0. QueryOver is actually quite powerful and flexible, as I aim to demonstrate in this series of blog posts.

There is not much in the way of official documentation for NHibernate in general, and even less for QueryOver. The only article on NHForge that I can find is here. While this is a good read for an introduction, it really doesn’t do QueryOver justice. There’s a lot of capability that’s not demonstrated there.

Overview of available querying technologies

If you’re using NHibernate, you’re probably aware that you have several options when you go to write a query:

  • SQL (via CreateSQLQuery)
  • HQL
  • LINQ to NHibernate
  • Criteria
  • QueryOver

Now, in some cases you must use SQL or HQL because of the type of query you’re writing. For the vast majority of simple to intermediate queries though, LINQ to NHibernate, QueryOver, and Criteria all seem like viable options.

Why use QueryOver?

Let’s assume that you’re working on a large project and using magic strings everywhere to write queries makes you a bit nervous. People are changing property and class names every day, potentially breaking queries across your application. In this case, your better-looking options are LINQ to NHibernate and QueryOver.

If you’ve tried to use LINQ to NHibernate for anything remotely complex, you know you’ll run into problems quickly. Currently you can’t even do a left join. What this means is if you have a left join in your query, or even if you think you’ll need one one day, you can’t currently use LINQ to NHibernate.

I’m not trying to pick on NHibernate’s LINQ provider or minimize the amount of work contributors have done towards it; I’m just pointing out that it’s incomplete and not a great option for querying right now. With this in mind, QueryOver is really your only viable option for writing queries with NHibernate. I’m sure the LINQ provider will only get better, but until then QueryOver is a good option.

jQueryUI Autocomplete 1.9

As you might have realized from my previous post, I have an affinity for the jQueryUI autocomplete widget. With 1.9, which was recently released, autocomplete got a little love, which is what I’ll focus on in this post. I’ll go over each change and what practical implications it has.

The response event

Previously, it wasn’t possible to determine when a search had completed unless results were returned (in which case the open event was triggered). There are several ways to get around this limitation, but none of them use autocomplete’s API. This limitation made it hard to perform actions if the search returned zero results.

Here’s what you would have had to do in jQueryUI 1.8:

Detecting no results in jQueryUI 1.8link
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var availableTags = [/* array of items */];

$("#auto").autocomplete({
    source: function (request, response) {
        var results = $.ui.autocomplete.filter(availableTags, request.term);

        if (!results.length) {
            $("#no-results").text("No results found!");
        } else {
            $("#no-results").empty();
        }

        response(results);
    }
});

Here’s what you can do in 1.9:

Detecting no results in jQueryUI 1.9link
1
2
3
4
5
6
7
8
9
10
11
12
var availableTags = [/* array of items*/];

$("#auto").autocomplete({
    source: availableTags,
    response: function(event, ui) {
        if (!ui.content.length) {
            $("#no-results").text("No results found!");
        } else {
            $("#no-results").empty();
        }
    }
});

Much cleaner. This works for an autocomplete-enabled input with a remote source as well:

Detecting no results with a remote sourcelink
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$("input").autocomplete({
    source: function(request, response) {
        $.ajax({
            url: "http://api.stackexchange.com/2.1/users",
            data: {
                pagesize: 10,
                order: 'desc',
                sort: 'reputation',
                site: 'stackoverflow',
                inname: request.term
            },
            dataType: 'jsonp'
        }).done(function(data) {
            if (data.items) {
                response($.map(data.items, function(item) {
                    return item.display_name;
                }));
            } else {
                response([]);
            }
        });
    },
    delay: 500,
    minLength: 3,
    response: function(event, ui) {
        if (!ui.content.length) {
            $("#message").text("No results found");
        } else {
            $("#message").empty();
        }
    }
});

Synchronous change event

This is fixing a subtle, but important, limitation in 1.8’s autocomplete implementation. The change event used a small timeout right after the blur occurred. Most of the time this didn’t cause a problem, but if you wanted to validate that the user selected an item from the suggestion menu, the user could actually submit the form before the change event fired. This is best seen with an example (click the result tab inside the fiddle):

If you select an item from the menu after searching, then click out of the field (enabling the submit button), then focus the input field again and change the input’s value to something not in the suggestion list, you can submit the form.

In 1.9, this works much better and you can prevent the user from submitting the form entirely:

Try following the steps for the 1.8 example, and you should not be able to submit the form.

Support for contentEditable

This enhancement allows you to attach autocomplete to a contentEditable element. This functionality was not possible in 1.8. This has some very cool applications that I’ll explore in a later blog post, but here’s a simple example:

Blurring a suggestion no longer changes the input’s value

This one is hard to explain, but follow the steps outlined in the 1.8 fiddle below to see the problem:

Now, follow the same instructions in 1.9:

See the difference? In 1.9, the input’s value is not reset when the menu item is hovered over.

Added experimental messages option for accessibility

The jQueryUI folks explain this one better than I can show with an example:

We now use ARIA live regions to announce when results become available and how to navigate through the list of suggestions. The announcements can be configured via the messages option, which has two properties: noResults for when no items are returned and results for when at least one item is returned. In general, you would only need to change these options if you want the string to be written in a different language. The messages option is subject to change in future versions while we work on a full solution for string manipulation and internationalization across all plugins. If you’re interested in the messages option, we encourage you to just read the source; the relevant code is at the very bottom of the autocomplete plugin and is only a few lines.

I’m not an accessibility expert, so I had to look up what ARIA live regions are. MDN has a great explanation:

In the past, a web page change could only be spoken in entirety which often annoyed a user, or by speaking very little to nothing, making some or all information inaccessible. Until recently, screen readers have not been able to improve this because no standardized markup existed to alert the screen reader to a change. ARIA live regions fill this gap and provide suggestions to screen readers regarding whether and how to interrupt users with a change.

So how does this apply to the autocomplete widget? Well, now when you search for an item, if you have a screen reader installed it will read you something like “1 result is available, use up and down arrow keys to navigate.”. Pretty cool, huh?

I’ve outlined each enhancement to jQueryUI autocomplete in the 1.9 release. There are some exciting possibilities, specifically with the contentEditable support and the exposure of the Menu widget as a first-class widget. I’ll be sure to follow up on those topics in a subsequent post.

jQueryUI Autocomplete: Top 5 Sources of Confusion

I’ve been answering jQueryUI autocomplete questions on StackOverflow now for over two and a half years and I’ve noticed that there are a few things that are always coming up. This post will attempt to clear up those sources of confusion.

jQuery Autocomplete vs. jQueryUI autocomplete

jQuery autocomplete is jQueryUI autocomplete’s predecessor. Despite the multiple messages and disclaimers on the legacy plugin’s page, there is still confusion about the documentation, functionality, and status of this plugin. For some reason, some folks do not notice the following message on Jörn Zaefferer’s documentation page for the plugin:

This plugin is deprecated and not developed anymore. Its successor is part of jQuery UI, and this migration guide explains how to get from this plugin to the new one. This page will remain as it is for reference, but won’t be updated anymore.

The link to the migration guide explains how to migrate your old code using the original, deprecated plugin with the new one provided by jQueryUI.

What format does my data need to be in?

Another source of confusion is exactly what format does the widget’s data source need to take? This is easy to see after viewing a few examples and reading the overview tab on the documentation page.

To summarize, the data that you send to the widget needs to be:

  1. An array of strings
  2. An array of objects. Each object should have a either a label property, a value property, or both.

An important point on #2 is that the object can contain other properties (besides label or value). This comes in handy when doing custom things with data.

I am using a server-side source and my data isn’t being filtered!

When you use a server-side resource, you are responsible for doing the filtering. Usually this occurs by building up a database query based on the term that the user searched for.

If you don’t want to filter your data with server-side code (which I highly recommend), you could retrieve all of the possible results via AJAX and then let the widget do the filtering. Here’s an example using StackOverflow’s API:

Letting jQueryUI do the filteringlink
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$.ajax({
    url: "http://api.stackexchange.com/2.1/users",
    data: {
        pagesize: 100,
        order: 'desc',
        sort: 'reputation',
        site: 'stackoverflow'
    },
    dataType: "jsonp"
}).success(function (data) {
    console.dir(data);
    var source = $.map(data.items, function (user) {
        return user.display_name;
    });

    $("input").autocomplete({
        source: source
    });
});

This may not be ideal depending on the size of the data you are processing. You may want to handle the filtering on the server rather than bogging the browser down with filtering through thousands of results.

I’m using a server-side resource that isn’t returning data in the format that autocomplete is expecting. What should I do?

You can supply a callback function to the source parameter of autocomplete. This allows you to use virtually any source as long as you format it correctly before passing it to the response function that autocomplete uses to populate the results. Here’s another example using the StackOverflow API:

Using a function with the “source” optionlink
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$("input").autocomplete({
    source: function(request, response) {
        $.ajax({
            url: "http://api.stackexchange.com/2.1/users",
            data: {
                pagesize: 10,
                order: 'desc',
                sort: 'reputation',
                site: 'stackoverflow',
                inname: request.term
            },
            dataType: 'jsonp'
        }).success(function(data) {
            var results = $.map(data.items, function(user) {
                return user.display_name;
            });

            response(results);
        });
    }
});

The key here is to use $.map to transform the results into the format that the widget expects (described above).

I want to implement tagging functionality. How can I go about that?

This is the most complex of the 5, but it is doable. Check out the multiple values demo for one way to do this.

I’ve demonstrated a more complex Google-plus like functionality in the answer to this question. Here’s an updated fiddle using the 2.1 version of the API.

Tagging functionalitylink
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
function split(val) {
    return val.split(/@\s*/);
}

function extractLast(term) {
    return split(term).pop();
}

function getTags(term, callback) {
    $.ajax({
        url: "http://api.stackexchange.com/2.1/tags",
        data: {
            inname: term,
            pagesize: 5,
            order: 'desc',
            sort: 'popular',
            site: 'stackoverflow'
        },
        success: callback,
        dataType: "jsonp"
    });
}

$(document).ready(function() {
    $("#tags")
    // don't navigate away from the field on tab when selecting an item
    .bind("keydown", function(event) {
        if (event.keyCode === $.ui.keyCode.TAB && $(this).data("autocomplete").menu.active) {

            event.preventDefault();
        }
    }).autocomplete({
        source: function(request, response) {
            if (request.term.indexOf("@") >= 0) {
                $("#loading").show();
                getTags(extractLast(request.term), function(data) {
                    response($.map(data.items, function(el) {
                        return {
                            value: el.name,
                            count: el.count
                        };
                    }));
                    $("#loading").hide();
                });
            }
        },
        focus: function() {
            // prevent value inserted on focus
            return false;
        },
        select: function(event, ui) {
            var terms = split(this.value);
            // remove the current input
            terms.pop();
            // add the selected item
            terms.push(ui.item.value);
            // add placeholder to get the comma-and-space at the end
            terms.push("");
            this.value = terms.join("");
            return false;
        }
    }).data("autocomplete")._renderItem = function(ul, item) {
        return $("<li>")
            .data("item.autocomplete", item)
            .append("<a>" + item.label + "&nbsp;<span class='count'>(" + item.count + ")</span></a>")
            .appendTo(ul);
    };
});

This demo is also useful because it shows a custom display of each tag including the count. Type @j to see tags starting with “j”.

jQueryUI autocomplete’s API may look simple at first glance, but this is a very extensible and capable plugin. Most people’s questions revolve around the source parameter for the plugin. Remember to look at your AJAX requests in Firebug or similar just to make sure the data you’re supplying to the widget is what you expect.

jQuery.aggregate: A Simple jQuery Aggregation Plugin

I’ve found myself needing to apply an aggregate function over a jQuery object several times. I decided to wrap the functionality in a plugin. I attempted to make $.aggregate and its little brother $.sum as close to LINQ’s aggregate and sum as possible. This goal obviously couldn’t be completely realized because of the dynamic nature of JavaScript. The biggest roadblock there is that you can’t really imply a “seed” value for an aggregating operation, since arrays can contain elements of various types in JavaScript.

Let’s take a look with an example:

1
2
3
4
5
6
7
8
var letters = "abcdefghijklmnopqrstuvwxyz";


var message = $.aggregate([0, 6, 6, 17, 4, 6, 0, 19, 4], function (working, element) {
    return working ? working + letters.charAt(element) : letters.charAt(element);
});

$("#message").text(message);

Here, we’re building up a message from an array of numbers that correspond to letters of the alphabet. We supplied the aggregate function with a source and a function describing how we wanted to build the aggregate, based on the current value we’re iterating over and the “working” aggregate (what we’ve built up so far).

The conditional operator inside the aggregate function is kind of awkward, so lets supply an initial “seed” value to the aggregate:

1
2
3
4
5
6
7
8
var letters = "abcdefghijklmnopqrstuvwxyz";


var message = $.aggregate([0, 6, 6, 17, 4, 6, 0, 19, 4], '',  function (working, element) {
    return working + letters.charAt(element);
});

$("#message").text(message);

Finally, we may want to supply some sort of final transformation function to our aggregated value. With the aggregate plugin, you can supply a function that will transform the aggregated value before returning it:

1
2
3
4
5
6
7
8
9
10
var letters = "abcdefghijklmnopqrstuvwxyz";


var message = $.aggregate([0, 6, 6, 17, 4, 6, 0, 19, 4], '',  function (working, element) {
    return working + letters.charAt(element);
}, function (value) {
    return value.toUpperCase();
});

$("#message").text(message);

That’s pretty much it for $.aggregate. You should be able to get pretty creative with it.

$.sum is just a convenient way to call $.aggregate. After implementing $.aggregate, $.sum was pretty easy. $.sum sheds some parameters, but is much more readable if all you’re doing is adding some values up:

1
2
3
var total = $.sum([0, 6, 6, 17, 4, 6, 0, 19, 4]);

$("#total").text(total);

Much neater right? You can also supply a transformation function that should return the item to be “summed”:

1
2
3
4
5
6
7
8
9
10
11
12
13
var groceries = [
    { name: 'bread', price: 2.50 },
    { name: 'bologna', price: 4.00 },
    { name: 'cheddar cheese', price: 3.50 },
    { name: 'potato chips', price: 3.00 }
];

var total = $.sum(groceries, function () {
    return this.price;
});


$("#total").text("$" + total);

That’s pretty much it for the “static” functions. Both $.sum and $.aggregate can take an object or an array of values to aggregate.

There are also “instance” methods on jQuery objects. These methods operate on jQuery objects:

1
2
3
4
5
6
7
8
9
10
11
12
$(document).ready(function () {
    $("td input:text").on("change", function () {
        var total = $("td input:text").sum(function () {
            var quantity = this.value
                , cost = parseFloat($(this).closest("tr").find(".price").text(), 10) || 0;

            return quantity * cost;
        });

        $("#total").text(total);
    });
});

(Aggregate follows the same pattern).

I’m also toying with the idea of adding $.min and $.max.

If you want to download, view the source, or run the unit tests associated with the plugin, I have it up on Github. Minified version coming soon.

Retrospective: 1 Year of StackOverflow

About one year ago this month I joined StackOverflow and started participating. I wanted to take a few minutes to reflect on my experience the site. First off, why did I start answering questions?

  • A living portfolio; My StackOverflow profile is something that’s constantly growing and that I can show to employers

  • Learning. Just spending time on the site allows you to learn new things.

  • Helping others. I use tons of free software every day. This is my way of giving back.

  • Pick up new problem-solving skills. Seeing the ways others answer questions gives you a view into their thought process. Seeing solutions that you wouldn’t necessarily have come up with yourself adds tools to your problem-solving toolbox.

When I started out, answering questions was a horrifying prospect: I’m going to put something on a high traffic programming site for other people to vote on? I was sure I’d mess up and get downvoted. Over 500 answers later though (and a 15K reputation), my stage fright has subsided.

I started out motivated by the reputation system (it’s addicting). After a while though, there has to be another motivator. For me, that motivator is the knowledge that with an answer you might be helping thousands of people all over the world Googling for a problem. How cool is that? There’s also the fact that you’re learning too when you answer a question.

I quickly figured out what makes a high-quality answer (beyond the qualities of a simply “good” answer):

  • Provides a working code sample

  • Provides a good explanation of that sample (just giving people code isn’t helpful after all)

  • Links to relevant documentation

  • Link to a demo, if possible

The last point (linking to a demo) turns out to be very important. If the asker can take your code and play around with it immediately, you’re much more likely to get more upvotes and that coveted green check mark. It’s hard to argue with a working example.

For that reason, I quickly gravitated to the JavaScript, jQuery, and jQueryUI tags. With those tags, I can almost always provide a working example in an answer. JavaScript sandbox site JSFiddle proved invaluable for providing working examples.

After spending some time in those tags, I noticed the “fastest gun in the west” problem. Since I wanted to provide high-quality answers in crowded tags (where answers to simple questions are posted very quickly), I started to get more specific in the tags I watched.

Specifically, I moved toward jQueryUI-Autocomplete. Not too many people were watching questions about that widget, so it gave me more time to come up with a high-quality answer. At the same time, jQueryUI is a popular enough framework that my answers did get attention.

This is probably my biggest tip for new StackOverflow answerers: If you’re overwhelmed by the quick answers and high activity in tags, find a specific type of question within that tag to focus on.

I also set goals while on StackOverflow. I wanted to get 10K reputation by the end of the year (which I’ve met and exceeded). I also wanted a silver badge (400 upvotes) in the jQuery tag. Setting goals like this keeps it interesting. You can set goals for each tag and increase your own knowledge of a particular tag substantially.

My goals for next year include:

  • Getting a gold badge in jQuery (1000 upvotes)

  • Getting a silver badge in C# (yep, I need to branch out)

  • Edit 600 posts

The most valuable thing I’ve gotten out of StackOverflow over the last year? Better communication skills. I believe my ability to communicate a technical problem with other technical people has improved substantially. Part of providing a good answer is providing a clear explanation. This skill translates directly into the professional world.

Good luck out there, and don’t hesitate to sign-up and start answering.