[SERVER-13928] Iteration over Map support Created: 13/May/14  Updated: 24/Jan/15  Resolved: 23/Jan/15

Status: Closed
Project: Core Server
Component/s: MapReduce
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Minor - P4
Reporter: Paolo Pino Assignee: Thomas Rueckstiess
Resolution: Incomplete Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
is related to SERVER-5947 Add ability to project key names as v... Closed
Participants:

 Description   

Iteration support would be very useful.
For example the use of map can be a workaround for the absense of multi $(update) support during update operation (the update query must contain the simply the key of object to update), but since iteration over map is unsupported i can't $unwind the map or use any other array operator of mongodb.

So the only solution for my problem is to create a separate collection and "dbref" it... .' (RELATIONAL DB STYLE)



 Comments   
Comment by Thomas Rueckstiess [ 16/Jul/14 ]

Thanks Paolo, I think I now understand what you'd like to be able to do: Iterating over documents (or objects, in Javascript language) where each iteration returns key/value, or at least the key, similar to Javascript's for (key in obj) loop.

Let's narrow the scope of this to the aggregation framework, as I don't know where else you'd want to use this feature.

In the aggregation framework, unwinding an array results in multiple documents where the original array is replaced with a single element of the array for each document.

For a document:

{
    friends: [
        {name: "Mario", email: "mario@email.it"},
        {name: "Giorigo", email: "giorgio@email.it"}
    ]
}

the aggregation framework's $unwind operator creates two documents like this:

{ friends: {name: "Mario", email: "mario@email.it"} }
{ friends: {name: "Giorgio", email: "giorgio@email.it"} }

But how would the syntax be if that was applied to objects rather than arrays (JS language). From a schema like yours:

{
    friends: {
        "mokitoUser": {name: "Mario", email: "mario@email.it"},
        "bro82": {name: "Giorigo", email: "giorgio@email.it"}
    }
}

Would you expect the resulting docs to look like this?

{ friends: { "mokitoUser": {name: "Mario", email: "mario@email.it"} } }
{ friends: { "bro82": {name: "Giorgio", email: "giorgio@email.it"} } }

I don't think this is very useful, as you have no way of introspecting the key names. You couldn't process the user names (I'm assuming "mokitoUser" and "bro82" are nick or user names) any further.

An alternative syntax could be

{ friends: { key: "mokitoUser", value: {name: "Mario", email: "mario@email.it"} } }
{ friends: { key: "bro82", value: {name: "Giorgio", email: "giorgio@email.it"} } }

This would give you access to key and value of each iteration and you could, for example, now filter out the users where friends.key is "bro82". However, the same can be achieved with a schema change, by pushing the user names into the user documents, e.g.:

{
    friends: [
        {username: "mokitoUser", name: "Mario", email: "mario@email.it"},
        {username: "bro82", name: "Giorigo", email: "giorgio@email.it"}
    ]
}

This schema has the added benefit that you could index username, which your original schema does not. Basically, I think the issue is that you're storing content in key names, rather than values, and this will get you into trouble in other places as well, because MongoDB doesn't have a way to introspect key names and query on those.

So for the use case you presented, I think the answer is to change the schema to make the user name a value rather than a key, and use arrays. Can you think of another use case where the proposed feature of iterating over objects would be useful and add something that can't currently be done? We're certainly open to suggestions for new features if the current ones are not sufficient, but we'd need to find a good use case that demonstrates this.

Thanks,
Thomas

Comment by Paolo Pino [ 08/Jul/14 ]

Sorry for the delay!

The map is of type <key,value>. The problem is that mongo iterate only over array, so for example i can't $unwind "friends" list inside an element like following:
{
name:"John",
surname:"Doe",
friends: {
"mokitoUser" :

{ "name" : "Mario", "email" : "my@email.it" }

,
"bro82" :

{ "name" : "Giorgio", "email" : "my@email.it" }

}
}

Obviously the problem isn't strictly related to aggregation framework, but occurs in all mongo functions that do iteration operation exclusive on array.

I hope i was clear

Thanks

Comment by Thomas Rueckstiess [ 02/Jul/14 ]

Hi Paolo,

Did you have the chance to read me previous comment yet? We can't proceed on this feature request without more details.

Thanks for your input,
Thomas

Comment by Thomas Rueckstiess [ 20/Jun/14 ]

Hi Paolo,

Can you explain in more detail the feature you're requesting?

If I understand correctly, you'd like a "map"-functionality like many programming languages offer. That is, you provide a function, and MongoDB applies the function to each document of a collection and updates it with the result of the function.

Is this correct? If not, can you elaborate?

Is this a request for the aggregation framework (you mention $unwind) or did you have a separate command in mind?

Note that the db.eval() method lets you do something like this already (see example on docs page).

Regards,
Thomas

Generated at Thu Feb 08 03:33:19 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.