Reputation: 23159
Given the following user object in MongoDB,
what would be the fastest way to search by relation.$.status == 'friends'
?
Need to find a way to find
in a user
collection's relation
data that contains an object with a value of "friends"
(see pseudo query below).
The keys for this particular collection have been set to uids, so assume that the "User Data" section below may not be altered.
User Data:
{
"_id": ObjectId('1a1a1a1a111a1a11a1a1a1a'),
"name": "Tester",
"relation": {
"2b2b2b2b2b2b2b2b2b2b2b": {
"status": 'friends',
"status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
},
"3c3c3c3c3c3c3c3c3c3c3c": {
"status": 'engaged',
"status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
}
}
}
Query:
var query = {
// pseudo, key-ignoring nested document search
'relation.$.status': 'friends'
}
var projection = {
'relation': 1
}
db.user.findOne(query, projection)
Desired Output:
{
"2b2b2b2b2b2b2b2b2b2b2b": {
"status": 'friends',
"status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
}
}
The obvious correction to the User Data structure should be making relation
an array of objects of which contain _id
and status
as keys. Kinda looking for a temporary shim here.
Upvotes: 2
Views: 1922
Reputation: 4464
You can apply mongodb Map/Reduce technique for this task.
1) map
function will determine nested objects from relation
object, which contain status
field equal to "friends"
value:
var map = function () {
for (var key in this.relation) {
var relation = this.relation[key];
if (relation.status == "friends")
emit(key, relation);
}
}
2) reduce
function will actually do nothing, just return single emitted relation:
var reduce = function (key, values) {
return values[0];
}
As a result you'll have collection with such objects:
{
_id: "2b2b2b2b2b2b2b2b2b2b2b",
value: {
status: "friends",
status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
}
}
If you decide to replace relation
object with array, you can use aggregation framework to construct similar query.
User Data:
{
_id: ObjectId("1a1a1a1a111a1a11a1a1a1a"),
name: "Tester",
relations: [
{
id: "2b2b2b2b2b2b2b2b2b2b2b",
status: "friends",
status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
},
{
id: "3c3c3c3c3c3c3c3c3c3c3c",
status: "engaged",
status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
}
]
}
Query:
db.collection.aggregate([
{ $unwind: "$relations" },
{ $match: { "relations.status": "friends" } },
{ $project: _id: 0,
id: "$relations.id",
status: "$relations.status",
status_changed_date: "$relations.status_chaged_date"
// etc...
}
])
Output:
{
id: "2b2b2b2b2b2b2b2b2b2b2b",
status: "friends",
status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
}
Upvotes: 1