2
{
"_id": "1",
"style": "13123",
"category": "dress",
"colors": {
    "Black": {
        "prestock": 50,
        "instock": 60,
        "inactive": 0
        },
    "Blue": {
        "prestock": 30,
        "instock": 0,
        "inactive": 0
        },
    "Red": {
        "prestock": 10,
        "instock": 60,
        "inactive": 0
        }
  }
}

i have above json, i need to access to prestock, instock, and inactive. but colors' value will change depending on styles. for example:

{
 "_id": "2",
 "style": "14321", 
 "category": "top",
 "colors": {
     "Green": {
        "prestock": 50,
        "instock": 60,
        "inactive": 0
         }, 
     "Yellow": {
        "prestock": 50,
        "instock": 60,
        "inactive": 0
         }
      }
}

how can i query this in mongodb? would this something that's related to Object.keys(obj)?

ps.if this is a duplicate question please guide me!

Thanks!

whoAmi21
  • 105
  • 1
  • 5
  • 14
  • what do you want to get from it? – user10 Oct 10 '13 at 16:28
  • @user10 i need to access the values of prestock, instock, and inactive – whoAmi21 Oct 10 '13 at 16:43
  • *accessing* the values isn't hard once you have the object in your code, you can use javascript there. If you want to *query* it, you'd have to know **what** you want to query, i.e. the `instock` value of the `Green` or the `Yellow` ones? Or do you want sth. like 'any color with instock > 0'? In that case, you'd better change the schema. – mnemosyn Oct 10 '13 at 17:11
  • @mnemosyn i need something like this: {"colors.anycolor":{"prestock":{$gte:30}}} – whoAmi21 Oct 10 '13 at 17:47
  • @wisleans You can't query like that, which is why you should probably stick to using an array like mnemosyn suggested in his answer. – JohnnyHK Oct 10 '13 at 18:51

3 Answers3

2

A query like {"colors.*.prestock" : {$gte:30}} isn't possible according to SERVER-267, and I doubt this will be supported in the next years.

Your best bet is to change the schema to an array:

colors: [
 { "color" : "Green", "instock" : 50, ... },
 { "color" : "Yellow", "instock" : 50, ... },
]

Then you can query

db.foo.find( {"colors.prestock" : {$gte:30}} )

Note that this will return the entire object, including all colors, i.e. also those for which the query constraint doesn't hold. This could be solved using the aggregation framework, but again, only using $unwind which also requires colors to be an array.

mnemosyn
  • 45,391
  • 6
  • 76
  • 82
0

Is this is what you are looking for? MongoDB Get names of all keys in collection

If not, then the Application must have a list of keys or enum values that has all the possible combinations, you will have to Query and go through them.

Community
  • 1
  • 1
rohit kotian
  • 130
  • 1
  • 13
  • similar i think! but would this work for objects? the link you've provided was in arrays – whoAmi21 Oct 10 '13 at 17:32
  • It should, give it a try! – rohit kotian Oct 10 '13 at 17:55
  • Keep in mind that Map/Reduce is mostly for large operations and has considerable overhead, so it's not useful for interactive queries. Also, you'd have to construct a wickedly complex `$or` query to 'fake' the wildcard behavior. – mnemosyn Oct 10 '13 at 18:00
  • @roko4326 oh wait.. no this is not what i need. how can i access to prestock without specifying "Black"? – whoAmi21 Oct 10 '13 at 18:01
0

A long time has passed since this question, however, I will update the answers because currently there is a method more efficient than previously posted:

It's possible to use the function $objectToArray inside a $project stage to get every key of {k1:v1, k2:v2, ..., kn:vn} and its value in an array in the form:

[
    {"k":"k1", "v":"v1"},
    {"k":"k2", "v":"v2"},
    ...
    {"k":"kn", "v": "vn"}
]

Then you can use the $unwind stage and use another $project to get the nested properties.

collection.aggregate([
{"$project": {"colors_array": {"$objectToArray": "$colors"}},
{"$unwind": {"path": "$colors_array"}},
{"$project": {"data_colors": "$colors_array.v"}}
])

I think this could be enough to have an array like this one:

[
  {
    "prestock": 50,
    "instock": 60,
    "inactive": 0
  },
  {
    "prestock": 30,
    "instock": 0,
    "inactive": 0
  }
  ...
]

But, in case you want to maintain the name of the color, you could obviate the last stage of the aggregate pipeline.