Merge Related Entities Using Multi Map/Reduce
A question came up in the mailing list regarding searching across related entities. In particular, the notion of a player and characters in a MMORPG game.
Join the DZone community and get the full member experience.
Join For FreeA question came up in the mailing list regarding searching across related entities. In particular, the scenario is the notion of a player and characters in MMORPG game.
Here is what a Player document looks like:
{
"Id": "players/bella@dona.self",
"Name": "Bella Dona",
"Billing": [ { ... }, { ... }],
"Adult": false,
"LastLogin": "2015-03-11"
}
And a player have multiple character documents:
{
"Id": "characters/1234",
"Name": "Black Dona",
"Player": "players/bella@dona.self",
"Race": "DarkElf",
"Level": 24,
"XP": 283831,
"HP": 438,
"Skills": [ { ... } , { ... } ]
}
{
"Id": "characters/1321",
"Name": "Blue Bell",
"Player": "players/bella@dona.self",
"Race": "Halfling",
"Level": 2,
"XP": 2831,
"HP": 18,
"Skills": [ { ... } , { ... } ]
}
{
"Id": "characters/1143",
"Name": "Brown Barber",
"Player": "players/bella@dona.self",
"Race": "WoodElf",
"Level": 44,
"XP": 983831,
"HP": 718,
"Skills": [ { ... } , { ... } ]
}
And what we want is an output like this:
{
"Id" : "players/bella@dona.self",
"Adult": false,
"Characters" : [
{ "Id": "characters/1234", "Name": "Black Dona" },
{ "Id": "characters/1321", "Name": "Blue Bell" },
{ "Id": "characters/1143", "Name": "Brown Barberl" },
]
}
Now, a really easy way to do that would be to issue two queries. One to find the player, and another to find its characters. That is actually the much preferred method to do this. But let us say that we need to do something that uses both documents types.
Give me all the players who aren’t adults that have a character over 40, for example. In order to do that, we are going to use a multi map reduce index to merge the two together. Here is how it is going to look like:
// map - Players
from player in docs.Players
select new
{
Player = player.Id,
Adult = player.Adult,
Characters = new object[0]
}
// map - Characters
from character in docs.Characters
select new
{
character.Player,
Adult = false,
Characters = new []
{
new { character.Id, character.Name }
}
}
// reduce
from result in results
group result by result.Player into g
select new
{
Player = g.Key,
Adult = g.Any(x=>x.Adult),
Characters = g.SelectMany(x=>x.Characters)
}
This gives you all the details, in a single place. And you can start working on queries from there.
Published at DZone with permission of Oren Eini, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments