Andre,
Interesting - I wouldn't dismiss a non-hashed key quite so quickly... If reads are specifying app_id,date range those would be targeted if you sharded on app_id, date but the question would then be how well will that balance the writes?
I'll give you an analogous example: Twitter.
When the writes come in, the most important thing is to not lose the writes and to ingest them as quickly as possible. That means they should be distributed evenly across the cluster so that you can add machines as the load goes up and gain capacity.
Now, how do the reads happen? You might read one person's timeline, you might read multiple people's timelines, but you're always reading the most recent data (almost exclusively).
So you want to shard by something like user, created_date:
for writes (single user can't tweet thousands of messages in the same second and usernames or _ids can be evenly distributed).
for single user reads - when you ask for my timeline it will be a targeted query (goes to my shard) and having created date adds data locality as recent tweets are guaranteed to be in one chunk even if I tweet so much that my data didn't fit in a single chunk (and it was split by date).
But what about the most common reads in Twitter - people wanting to read the timeline of all of their friends, or all of the weeks on a particular keyword or hashtag?
Well, a few things - yes it will be a scatter gather query. But does the data have to come back strictly in order? Nope.
Does it matter if you only return data from one shard or ten (out of hundreds) of shards? Again, no. The most important thing is to return some (correct) data *fast*. But all the data? I don't think anyone would ever want (or expect) that.
So for something like twitter the trade-off is easy in a conflict like that - writes are important but individual reads are basically not. Or rather they are somewhat interchangeable.
In your case it looks like the writes must get balanced well, but the reads - generally reports and map/reduce type jobs are *not* sensitive to latency and in fact you might want to off load them to designated secondaries (if you can) so that they don't slow down the writes (they might cause "reporting" secondaries to lag sometimes, but if they are okay with stale data as historical reports frequently are then it's no big deal).
You want to be careful with scatter-gather map/reduce jobs or long running unindexed queries over all your data - they will basically mess with your working set and RAM utilization on every single shard!
Luckily they are frequently not required to complete too fast. By the way, if you are going to move to 2.6 soon, maybe you can replace some of the map/reduce jobs by aggregation framework - it will be a lot faster.
Asya