Search:

Search all manuals
Search this manual
Manual
Membase and ASP.NET MVC 3 Tutorial
Additional Resources
Community Wiki
Community Forums
Couchbase SDKs
Parent Section
Membase and ASP.NET MVC 3 Tutorial
Chapter Sections
Chapters

8. Stage 7: Making the application a little more social

Web applications tend to be more fun if there's some sort of social aspect to them. Usually a diary application would be a private affair. Let's add a social aspect to this to make it a little more interesting.

The application should break down each diary entry into a list of words. Every user will have a list of every word they have ever written in a diary entry. Each word will also have a user list associated with it, effectively keeping track of every user who has ever said that word in one of their diary entries.

Add the content of Listing 19 to the end of the MakeEntry action, just before the return statement.

Listing 19: Creating the word lists.

// Finally we want to store each word in the diary entry
// into the database such that a map of words to users
// is produced in order to make this application a little
// more social.
var wordList = Regex.Split(entry.Text, @"\W+")
    .ToList()
    .ConvertAll(d => d.ToLower());

var wordsKey = user.UserId + ".Words";

foreach (var word in wordList)
{
    AddToListWithCas(client, wordsKey, word);
    AddToListWithCas(client, word + ".Users", user.UserId);
}

This block of code breaks the entry text down into words using a regular expression, and uses a little LINQ to turn the array of strings into a list and convert every word to lower case. A key is created simply be appending ".Words" to the user's UserId guide. It doesn't matter what is in the key, as long as you remember what the key was. This effectively makes a relation between the list of words and the user.

The code then iterates over the list of words, and reuses the AddToListWithCas method discussed earlier to add them first to the user's word list, and finally to a global word list that relates each word to all of the users who have ever said it. This is definitely where the power of a NoSQL database shines. We can just make links between information by making specially formatted keys pointing to objects. In this case we're adding the userId to a list of objects pointed to by the key word.Users where the word is replaced by the current word.

Now you will need to make a final modification to the Index method of the HomeController to include the logic for turning these lists of words into a list of names of the users who are using the same language you are.

Listing 20, update Index in HomeController.cs

// Now, do a calculation to discover the top three users who use
// similar words in their diary entries.

// Get the user's word list
var wordlist = client.Get<List<string>>(user.UserId + ".Words");

if (wordlist != null)
{
    var userListKeys = wordlist.ConvertAll(k => k + ".Users");
    var userLists = client.Get(userListKeys)
        .Values
        .Cast<List<Guid>>();

    // Calculate the count of users who have used
    // the same words that the current user has

    var userCounts = new Dictionary<Guid, int>();

    foreach (var list in userLists)
    {
        foreach (var userId in list)
        {
            // Skip ourselves
            if (userId == user.UserId) continue;

            if (userCounts.ContainsKey(userId))
            {
                userCounts[userId] = userCounts[userId] + 1;
            }
            else
            {
                userCounts[userId] = 1;
            }
        }
    }

    // Make a final list of users by ordering by the counts
    // in the userCounts dictionary.
    var kindred = new List<User>();
    foreach (var item in userCounts.OrderByDescending(key => key.Value))
    {
        kindred.Add(client.Get<User>(item.Key.ToString()));
        if (kindred.Count > 2)
            break;
    }

    ViewData["KindredUsers"] = kindred;
}

Effectively each user's word lists are obtained, and the keys to the global list of words to users is created. This is used in another multi-get operation whose values are converted to a lists of Guids. Then these lists are iterated, to tabulate a total count of the userIds. We're making the assumption that these counts are all we need to determine who has been using similar words to us. These are then ordered by maximum count first, and added to a KindredUsers list.

The Index view must now be modified to present these kindred users. Listing 21 should be added before the last line of the Index.cshtml file.

Listing 21, update Index.cshtml.

@if (ViewData.ContainsKey("KindredUsers")) {

    var kindred = ((IList<User>)ViewData["KindredUsers"]);

    <h2>Kindred Users</h2>

    if (kindred.Count > 0)
    {
        <ul>
        @foreach (var user in kindred)
        {
            <li>@user.FullName</li>
        }
        </ul>
    }
    else
    {
        <p>You currently have no kindred users.</p>
    }
}

Improvements could easily be made to this application. You may want to allow users to contact each other by providing a way to drop notes. You may also improve the word ratings by removing common stop-words (such as 'a', 'an', 'or', 'the', 'in' and so on) or maybe skipping all short words altogether.

I'm sure you've got all sorts of ideas about how to apply Membase to your latest projects, and we hope you've enjoyed this tutorial. You will find the final source code in the file dotnet-membase-tutorial.zip.