Need help on operation like update,delete,add,upsert,delete on below document of MongoDB.
Below is MongoDB document that exists in temp collection.
{
"local_id" : "1841",
"name_first" : "tiger",
"name_last" : "lion",
"address" : [
{
"id" : 1,
"address_type" : "Home",
"city" : "Delhi",
"country" : "",
"po_box" : ""
},
{
"id" : 2,
"address_type" : "Work",
"city" : "",
"country" : "",
"po_box" : ""
}
],
"email" : [
{
"email_id" : "blah#gmail.com",
"id" : 1,
"type" : "Home"
},
{
"email_id" : "Pearl1#gmail.com",
"id" : 2,
"type" : "Work"
}
],
"phone_number" : [
{
"id" : 1,
"no" : "+911234567890",
"type" : "Mobile"
},
{
"id" : 2,
"no" : "+917894561230",
"type" : "work"
}
]
}`
Now I have some document like below, i want query that will compare,add,update,delete on my above document.
`
{
"local_id" : "1730",
"name_first" : "lion",
"name_last" : "king",
"address" : [
{
"id" : 1,
"address_type" : "Home",
"city" : "Delhi",
"country" : "India",
"po_box" : "110041"
},
{
"id" : 2,
"address_type" : "Work",
"city" : "Delhi-NCR",
"country" : "India",
"po_box" : "110048"
},
{
"id" : 3,
"address_type" : "Work",
"city" : "Delhi-NCR",
"country" : "Indai",
"po_box" : "110048"
}
],
"email" : [
{
"email_id" : "updatethis#gmail.com",
"id" : 1,
"type" : "Home"
},
{
"email_id" : "Pearl1#gmail.com",
"id" : 2,
"type" : "Work"
},
{
"email_id" : "addthisarray#gmail.com",
"id" : 3,
"type" : "personal"
}
],
"phone_number" : [
{
"id" : 1,
"no" : "+911234567890",
"type" : "Mobile"
}
/*second array not here so remove that array from that document*/
]
}`
You can save function on server as you can call that function to get the differences, as below.
db.system.js.save({
_id: "getupdatedArray",
value: function(obj1, obj2) {
var VALUE_CREATED = 'created';
var VALUE_UPDATED = 'updated';
var VALUE_DELETED = 'deleted';
var VALUE_UNCHANGED = 'unchanged';
function map(obj1, obj2) {
if (isValue(obj1) || isValue(obj2)) {
return {
type: compareValues(obj1, obj2),
old: obj1,
new: obj2
};
}
var diff = {};
for (var key in obj1) {
if (isFunction(obj1[key])) {
continue;
}
var value2 = undefined;
if ('undefined' != typeof(obj2[key])) {
value2 = obj2[key];
}
diff[key] = map(obj1[key], value2);
}
for (var key in obj2) {
if (isFunction(obj2[key]) || ('undefined' != typeof(diff[key]))) {
continue;
}
diff[key] = map(undefined, obj2[key]);
}
return diff;
}
function compareValues(value1, value2) {
if (value1 === value2) {
return VALUE_UNCHANGED;
}
if ('undefined' == typeof(value1)) {
return VALUE_CREATED;
}
if ('undefined' == typeof(value2)) {
return VALUE_DELETED;
}
return VALUE_UPDATED;
}
function isFunction(obj) {
return {}.toString.apply(obj) === '[object Function]';
}
function isArray(obj) {
return {}.toString.apply(obj) === '[object Array]';
}
function isObject(obj) {
return {}.toString.apply(obj) === '[object Object]';
}
function isValue(obj) {
return !isObject(obj) && !isArray(obj);
}
return map(obj1, obj2);
}
})
Then you can call function as below..
db.loadServerScripts();
getupdatedArray({"a": "abc"}, {"a": "a111", "b": "bbb"});
This will give you result as below:
{
"a" : {
"type" : "updated",
"old" : "abc",
"new" : "a111"
},
"b" : {
"type" : "created",
"old" : undefined,
"new" : "bbb"
}
}
Thanks
Satish Lakhani
Related
I'd like to update the value of the key shouldSendAlert in the following document:
{
"_id" : ObjectId("5c61c4db46d18e1092c5b024"),
"service" : "SRVPVD",
"menu" : [
{
"sub" : [
{
"options" : [
{
"item" : [
{
"name" : "",
"actions" : [
{
"name" : "communicateClient",
"value" : true
},
{
"name" : "shouldSendAlert",
"value" : false
}
]
}
],
"name" : "Technology Support"
},
{
"item" : [
{
"name" : "",
"actions" : [
{
"name" : "communicateClient",
"value" : true
}
]
}
],
"name" : "Company Support"
}
],
"name" : "Support"
},
{
"name" : " FAQ"
}
],
"name" : "Help"
}
]
}
I've managed to do this, querying the document using a multiple $elemMatch query, and using forEach to run through the nested arrays in order to alter the value of shouldSendAlert:
{
let menuItems = db.getCollection('menumodels').find({menu: {$elemMatch: {name: 'Help',sub: {$elemMatch: {name: 'Support',motivos: {$elemMatch: {name: 'Technology Support'}}}}}}});
menuItems.forEach((r) => {
r.menu.forEach(menuItem => {
if (menuItem.name == 'Help') {
menuItem.sub.forEach(sub => {
if (sub.name == 'Support') {
sub.motivos.forEach(motivo => {
if (motivo.name == "Technology Support") {
motivo.item[0].actions.forEach(action => {
if (action.name == 'shouldSendAlert') {
action.value = true;
db.getCollection('menumodels').update({_id: r._id}, {$set: {menu: r.menu}})
}
})
}
})
}
})
}
})
});
}
Is it - regarding performance - necessary, to code this MongoDB query
or update logic into a smarter form? Does the multiple use of $elemMatch affect performance?
I have several hundred thousands of documents in mongoDB to update.
here is an example of existing documents from collection Users:
{
"_id" : "549120bcf5115900124fb6e1",
"user" : "Tom",
"country" : "United Kingdom",
"province" : "North Yorkshire",
"city" : "York",
"organization" : ""
},
{
"_id" : "143184fbf5482260184ac6e2",
"user" : "Jack",
"country" : "Not Listed",
"province" : "",
"city" : "",
"organization" : "United Nations"
},
{
"_id" : "1234567890123456748979",
"user" : "Sarah",
"country" : "Not Listed",
"province" : "",
"city" : "",
"organization" : ""
},
{
"_id" : "98765432411654987654",
"user" : "Mat"
}
Each document has the possibility to have values in these fields :
a country, a province, and a city
or a country and a state
and here is the sample from another collection Countries:
{
"_id" : "123456789",
"key" : "Not Listed",
"uuid" : "ca55b53a-ef5b-43ed-90ed-b857f45ddb6d",
"organization" : [
{
"key" : "United Nations",
"uuid" : "1c4ae4c6-00c5-405d-98fa-ca7cc9edc72a"
},
{
"key" : "FIFA",
"uuid" : "11cfe606-821f-40fb-b1d0-bb7f9abb21dc"
}
],
"province" : [],
},
{
"_id" : "1123465498742",
"key" : "United Kingdom",
"uuid" : "d756e167-25ec-4aa9-b231-4dbf6d4bfce4",
"organization" : [],
"province" : [
{
"key" : "North Yorkshire",
"uuid" : "73d07c77-eba4-4dfa-9ada-e0ba8d8a2d55",
"city" : [
{
"key" : "York",
"uuid" : "80fd18a6-c4eb-4fb9-b591-6cca62319ba7"
},
{
"key" : "Middlesbrough",
"uuid" : "26a277c4-8640-4959-a64a-00f3727975f4"
}
],
},
{
"key" : "Oxfordshire",
"uuid" : "f7b5a570-df42-4520-ba3a-8bdcdd00e7d4",
"city" : [
{
"key" : "Oxford",
"uuid" : "b931865c-a363-4958-b7e7-5503fe674eb0"
},
{
"key" : "Banbury",
"uuid" : "b8d4c63a-75a9-4c3c-a4cd-d315f06a92e0"
}
],
}
]
}
The idea is to look up the country/organization/province/city field value from documents in Users collection and update them based on the uuid value of the Countries collection.
So the result will look like something like this:
{
"_id" : "549120bcf5115900124fb6e1",
"user" : "Tom",
"country" : "d756e167-25ec-4aa9-b231-4dbf6d4bfce4", // uuid of United Kingdom
"province" : "73d07c77-eba4-4dfa-9ada-e0ba8d8a2d55", // uuid of North Yorkshire
"city" : "80fd18a6-c4eb-4fb9-b591-6cca62319ba7", // uuid of York
"state" : ""
},
{
"_id" : "143184fbf5482260184ac6e2",
"user" : "Jack",
"country" : "ca55b53a-ef5b-43ed-90ed-b857f45ddb6d", // uuid of Not Listed
"province" : "",
"city" : "",
"state" : "1c4ae4c6-00c5-405d-98fa-ca7cc9edc72a" // uuid of United Nations
},
{
"_id" : "1234567890123456748979",
"user" : "Sarah",
"country" : "ca55b53a-ef5b-43ed-90ed-b857f45ddb6d", // uuid of Not Listed
"province" : "",
"city" : "",
"state" : ""
},
{
"_id" : "98765432411654987654",
"user" : "Mat"
}
The dependency of the fields are the following:
Country > Province > City
Or:
Country > Organization
It is possible that a parent field exists, but its child field doesn't exist or is empty.
How can I update these multidimensional arrays using mongo script rules?
Here is my attempt, but this is a lot of for loops, and not sure how to do the mongodb find/update/save part.. could somebody help to achieve it?
var usrCountry, uuidcountry, usrProvince, uuidprovince, usrOrg, uuidorg, usrCity, uuidcity;
for (var i = 0; i < users.length; i++) {
usrCountry = users[i].country;
usrProvince = users[i].province;
usrOrg = users[i].organization;
usrCity = users[i].city;
for (var j = 0; j < countries.length; j++) {
if (countries[j].key === usrCountry) {
uuidcountry = countries[j].uuid;
console.log('uuidcountry: ', uuidcountry)
if (countries[j].province.length){
for (var k = 0; k < countries[j].province.length; k++) {
if (countries[j].province[k].key === usrProvince){
uuidprovince = countries[j].province[k].uuid;
console.log('uuidprovince', uuidprovince)
for (var l = 0; l < countries[j].province[k].city.length; l++) {
if (countries[j].province[k].city[l].key === usrCity){
uuidcity = countries[j].province[k].city[l].uuid
console.log('uuidcity: ', uuidcity)
}
}
}
}
}
}
}
}
You can try do this with aggregation pipeline, and use that info to update
db.u.aggregate(
[
{
$lookup: {
from : "c",
localField : "country",
foreignField : "key",
as : "countryInfo"
}
},
{
$project: {
"_id" : 1,
"user" : 1,
"province" : 1,
"country" : 1,
"city" : 1,
"organization" : 1,
"country_uuid" : {$arrayElemAt : ["$countryInfo.uuid",0]},
"province_uuid" : { $arrayElemAt : [{ $map : { input : { $filter : { input : {$arrayElemAt : ["$countryInfo.province" ,0 ]} , as : "pro", cond : { $eq : [ "$$pro.key", "$province" ] } } } , as : "pr", in : "$$pr.uuid" } }, 0 ] },
"city_uuid" : {$arrayElemAt : [{$map : { input : { $arrayElemAt : [ {$filter : { input : { $map : { input : { $arrayElemAt : ["$countryInfo.province.city" ,0 ] }, as : "ct", in : { $filter : { input : "$$ct" , as : "ctyy", cond : { $eq : ["$$ctyy.key", "$city"] } } } } }, as : "o", cond : {$ne : [ {$size : "$$o"} , 0 ] } } } , 0]}, as : "o", in :"$$o.uuid"}}, 0]}
}
}
]
)
result
> db.u.aggregate( [ { $lookup: { from : "c", localField : "country", foreignField : "key", as : "countryInfo" } }, { $project: { "_id" : 1, "user" : 1, "province" : 1, "country" : 1, "city" : 1, "organization" : 1, "country_uuid" : {$arrayElemAt : ["$countryInfo.uuid",0]}, "province_uuid" : { $arrayElemAt : [{ $map : { input : { $filter : { input : {$arrayElemAt : ["$countryInfo.province" ,0 ]} , as : "pro", cond : { $eq : [ "$$pro.key", "$province" ] } } } , as : "pr", in : "$$pr.uuid" } }, 0 ] }, "city_uuid" : {$arrayElemAt : [{$map : { input : { $arrayElemAt : [ {$filter : { input : { $map : { input : { $arrayElemAt : ["$countryInfo.province.city" ,0 ] }, as : "ct", in : { $filter : { input : "$$ct" , as : "ctyy", cond : { $eq : ["$$ctyy.key", "$city"] } } } } }, as : "o", cond : {$ne : [ {$size : "$$o"} , 0 ] } } } , 0]}, as : "o", in :"$$o.uuid"}}, 0]} } } ] ).pretty()
{
"_id" : "549120bcf5115900124fb6e1",
"user" : "Tom",
"country" : "United Kingdom",
"province" : "North Yorkshire",
"city" : "York",
"organization" : "",
"country_uuid" : "d756e167-25ec-4aa9-b231-4dbf6d4bfce4",
"province_uuid" : "73d07c77-eba4-4dfa-9ada-e0ba8d8a2d55",
"city_uuid" : "80fd18a6-c4eb-4fb9-b591-6cca62319ba7"
}
I am working on a reactjs project - where I have say an English url like "/en/how-it-works" and wish to loop through the json tree to find the position/child level at which this link is set -- and find its German matching pair.
So basically -- a function that is given the English url, returns the German url
so --
lng - return de
currenlang - en
pairUrl - /en/how-it-works
return /de/anleitung
or
lng - return en
currentlang de
pairUrl - /de/beliebte-projekte/bundle1
return /en/popular-projects/bundle1
//function
getLanguagePair (lng, currentLng, pairUrl) {
// 'find url in json tree'
console.log('linkTreeObject', linkTreeObject.langs)
var obj = {}
//find position in tree
if(currentLng === 'de'){
obj = linkTreeObject.langs[0].lines.menu
} else {
obj = linkTreeObject.langs[1].lines.menu
}
var pos = []
for (var k in obj) {
if (!obj.hasOwnProperty(k)) continue
if (obj[k].link === pairUrl) {
pos[k]
}
}
console.log('pos' , pos)
if (lng === 'de') {
return '/de/link'
} else {
return '/en/link'
}
}
//json file
{
"langs" : [
{
"lang" : "de",
"lines" : {
"menu" : [
{
"title": "Anleitung",
"link": "/de/anleitung",
"children" : []
},
{
"title": "Beliebte Projekte",
"link": "/de/beliebte-projekte",
"children" : [
{
"title" : "Bundle1",
"link" : "/de/beliebte-projekte/bundle1"
},
{
"title" : "Bundle2",
"link" : "/de/beliebte-projekte/bundle2"
}
]
}
],
"sign_in" : "Login"
}
},
{
"lang" : "en",
"lines" : {
"menu" : [
{
"title": "How it works",
"link": "/en/how-it-works",
"children" : []
},
{
"title": "Popular Projects",
"link": "/en/popular-projects",
"children" : [
{
"title" : "Bundle1",
"link" : "/en/popular-projects/bundle1"
},
{
"title" : "Bundle2",
"link" : "/en/popular-projects/bundle2"
}
]
}
],
"sign_in" : "Sign in"
}
}
]
}
You will have to loop through 'en' and 'de' simultaneously and use recursion since you have nested links. Here is my version. I already took out the 'en' and 'de' array and used them in the function.
var obj ={
"langs" : [
{
"lang" : "de",
"lines" : {
"menu" : [
{
"title": "Anleitung",
"link": "/de/anleitung",
"children" : []
},
{
"title": "Beliebte Projekte",
"link": "/de/beliebte-projekte",
"children" : [
{
"title" : "Bundle1",
"link" : "/de/beliebte-projekte/bundle1"
},
{
"title" : "Bundle2",
"link" : "/de/beliebte-projekte/bundle2"
}
]
}
],
"sign_in" : "Login"
}
},
{
"lang" : "en",
"lines" : {
"menu" : [
{
"title": "How it works",
"link": "/en/how-it-works",
"children" : []
},
{
"title": "Popular Projects",
"link": "/en/popular-projects",
"children" : [
{
"title" : "Bundle1",
"link" : "/en/popular-projects/bundle1"
},
{
"title" : "Bundle2",
"link" : "/en/popular-projects/bundle2"
}
]
}
],
"sign_in" : "Sign in"
}
}
]
};
var en = obj.langs[1].lines.menu;
var de = obj.langs[0].lines.menu;
function GetUrl(enUrl, enMenu, deMenu)
{
var deUrl;
for(var i = 0; i < enMenu.length; i++)
{
if(enMenu[i].link == enUrl)
{
deUrl = deMenu[i].link;
break;
}
else
{
if(enMenu[i].children && enMenu[i].children.length > 0)
{
deUrl = GetUrl(enUrl,enMenu[i].children, deMenu[i].children )
}
}
}
return deUrl;
}
console.log(GetUrl("/en/how-it-works", en, de));
console.log(GetUrl("/en/popular-projects", en, de));
console.log(GetUrl("/en/popular-projects/bundle1", en, de));
console.log(GetUrl("/en/popular-projects/bundle2", en, de));
I am looking for a way to sort my three main JSON keys (neutral, positive, negative) using their children y-keys' values.
This is how the JSON object is set up:
{
"chartSeries" : {
"negative" : [ {
"y" : 1505,
"url" : "http://www.test.com/1"
}, {
"y" : 425,
"url" : "http://www.test.com/2"
}, {
"y" : 1046,
"url" : "http://www.test.com/3"
} ],
"neutral" : [ {
"y" : 10,
"url" : "http://www.test.com/4"
}, {
"y" : 1,
"url" : "http://www.test.com/5"
}, {
"y" : 2,
"url" : "http://www.test.com/6"
} ],
"positive" : [ {
"y" : 230,
"url" : "http://www.test.com/7"
}, {
"y" : 50,
"url" : "http://www.test.com/8"
}, {
"y" : 483,
"url" : "http://www.test.com/9"
} ]
}
}
Let's say I want to sort the negative values descending by y's value, then my JSON should look like this:
{
"chartSeries" : {
"negative" : [ {
"y" : 1505,
"url" : "http://www.test.com/1"
}, {
"y" : 1046,
"url" : "http://www.test.com/3"
}, {
"y" : 425,
"url" : "http://www.test.com/2"
} ],
"neutral" : [ {
"y" : 10,
"url" : "http://www.test.com/4"
}, {
"y" : 2,
"url" : "http://www.test.com/6"
}, {
"y" : 1,
"url" : "http://www.test.com/5"
} ],
"positive" : [ {
"y" : 230,
"url" : "http://www.test.com/7"
}, {
"y" : 483,
"url" : "http://www.test.com/9"
}, {
"y" : 50,
"url" : "http://www.test.com/8"
} ]
}
}
note how the negative elements are ordered by their descending y-values and neutrals' and postives' values are ordered exactly in the same sequence.
I tried parsing it as Javascript object using JSON.parse() and then using a sort function:
function sortResults(data, prop, asc) {
sorted_data = data.sort(function(a, b) {
if (asc) return (a[prop] > b[prop]);
else return (b[prop] > a[prop]);
});
return sorted_data;
}
But I just get "TypeError: data.sort is not a function" in my debugger.
Any explanations or advices are kindly appreciated!
And do not forget to add a paseInt() to ensure all the keys are integers. I had somy funny time figuring that back in the days.
I'll stick with JSON.sortify (https://www.npmjs.com/package/json.sortify) as it perfectly suits my needs.
The code behind that magical function:
function sortKeys(o) {
if (Array.isArray(o)) {
return o.map(sortKeys)
} else if (o instanceof Object) {
var _ret = function() {
var numeric = [];
var nonNumeric = [];
Object.keys(o).forEach(function(key) {
if (/^(0|[1-9][0-9]*)$/.test(key)) {
numeric.push(+key)
} else {
nonNumeric.push(key)
}
});
return {
v: numeric.sort(function(a, b) {
return a - b
}).concat(nonNumeric.sort()).reduce(function(result, key) {
result[key] = sortKeys(o[key]);
return result
}, {})
}
}();
if (typeof _ret === "object") return _ret.v
}
return o
};
And that's it.
I have a collection in which each object contains details of the user along with the comments user has given on specific products which is given below
{
"_id" : ObjectId("51efcbc8786df13540e46887"),
"value": {
"UserDetails" : [
[
{
"country" : "CA",
"gender" : "M",
"age" : "18",
"userIdtemp" : ObjectId("51efcbc8786df13540e46887")
}
]
],
"comments" : [
{
"commentId" : ObjectId("51efcc41786df13540e46891"),
"comment" : "Hey, what's up?",
"created" : ISODate("2013-07-24T12:44:49.400Z"),
"productId" : ObjectId("51efcbd4786df13540e4688c"),
"userId" : ObjectId("51efcbc8786df13540e46887")
},
{
"commentId" : ObjectId("51efcc43786df13540e46893"),
"comment" : "Cool",
"created" : ISODate("2013-07-24T12:44:51.004Z"),
"productId" : ObjectId("51efcbd2786df13540e4688b"),
"userId" : ObjectId("51efcbc8786df13540e46887")
}
]
}
}
{
"_id" : ObjectId("51efcbc8786df13540e46888"),
"value" : {
"UserDetails" : [
[
{
"country" : "US",
"gender" : "M",
"age" : "25",
"userIdtemp" : ObjectId("51efcbc8786df13540e46888")
}
]
],
"comments" : [
{
"commentId" : ObjectId("51efcc41786df13540e46892"),
"comment" : "Not much",
"created" : ISODate("2013-07-24T12:44:49.475Z"),
"productId" : ObjectId("51efcbd4786df13540e4688c"),
"userId" : ObjectId("51efcbc8786df13540e46888")
}
]
}
}
{
"_id" : ObjectId("51efcbc8786df13540e46889"),
"value" : {
"UserDetails" : [
{
"country" : "US",
"gender" : "F",
"age" : "13",
"userIdtemp" : ObjectId("51efcbc8786df13540e46889")
}
]
}
}
I have to extract comments separately along with there userDetails with key as productId so i have written map something like following
mapCommentsFrom = function(){
if("comments" in this.value)
{
for(var idx = 0;idx<this.value.comments.length;idx++){
var key = this.value.comments[idx].productId;
var value = [{
commentId: this.value.comments[idx].commentId,
comment:this.value.comments[idx].comment,
created:this.value.comments[idx].created,
productId:this.value.comments[idx].productId,
userId:this.value.comments[idx].userId,
country:this.value.UserDetails[0][0].country,
gender:this.value.UserDetails[0][0].gender,
age : this.value.UserDetails[0][0].age
}]
}
}
emit(key,value);
}
reduceFrom = function(k,values){
return values;
}
but where ever the number of comments are more than one i am getting only the last comment along with user details and other's key as well as value is coming null. Something like this
{ "_id" : null, "value" : null }
{
"_id" : ObjectId("51efcbd2786df13540e4688b"),
"value" : [
{
"length" : 2,
"commentId" : ObjectId("51efcc43786df13540e46893"),
"comment" : "Cool",
"created" : ISODate("2013-07-24T12:44:51.004Z"),
"productId" : ObjectId("51efcbd2786df13540e4688b"),
"userId" : ObjectId("51efcbc8786df13540e46887"),
"country" : "CA",
"gender" : "M",
"age" : "18"
}
]
}
{
"_id" : ObjectId("51efcbd4786df13540e4688c"),
"value" : [
{
"length" : 1,
"commentId" : ObjectId("51efcc41786df13540e46892"),
"comment" : "Not much",
"created" : ISODate("2013-07-24T12:44:49.475Z"),
"productId" : ObjectId("51efcbd4786df13540e4688c"),
"userId" : ObjectId("51efcbc8786df13540e46888"),
"country" : "US",
"gender" : "M",
"age" : "25"
}
]
}
Can somebody please help me as to what i am missing?
Thanks for help in advance
I cannot add comments due to reputation. But had you considered using the aggregation framework.
The $unwind operator will return you an array of sub documents quite easily and it's faster than using map/reduce.
I'm not sure it will exactly do what you're looking for but may help.
Take a look, http://docs.mongodb.org/manual/reference/aggregation/unwind/
Its because you are not emitting them in the map function.
Move the emit function inside the for loop.
mapCommentsFrom = function(){
if("comments" in this.value){
for(var idx = 0;idx<this.value.comments.length;idx++){
var key = this.value.comments[idx].productId;
var value = {
commentId: this.value.comments[idx].commentId,
comment:this.value.comments[idx].comment,
created:this.value.comments[idx].created,
productId:this.value.comments[idx].productId,
userId:this.value.comments[idx].userId,
country:this.value.UserDetails[0][0].country,
gender:this.value.UserDetails[0][0].gender,
age : this.value.UserDetails[0][0].age
}
emit(key,value);
}
}
}
Then you may also need to rewrite your reduce function to something like this
reduceFrom = function(k,valueArray){
var returnData = { values : [] } ;
for(var i=0;i<valueArray.length;i++)
returnData.values.push(valueArray[i]);
return returnData;
}
By far the easiest is to just use the aggregation framework for this. The aggregation framework allows you to execute operators on data, there is $match for doing queries (like find()) and various others. See for more information: http://docs.mongodb.org/manual/core/aggregation/
The aggregation framework also has an $unwind function that does exactly what you want. You use it like:
db.collection.aggregate( [
{ $unwind: '$value.comments' },
{ $project: {
_id: '$value.comments.productId',
value: 1
} }
] );
On your sample documents, this returns:
{
"result" : [
{
"_id" : ObjectId("51efcbd4786df13540e4688c"),
"value" : {
"UserDetails" : [
[
{
"country" : "CA",
"gender" : "M",
"age" : "18",
"userIdtemp" : ObjectId("51efcbc8786df13540e46887")
}
]
],
"comments" : {
"commentId" : ObjectId("51efcc41786df13540e46891"),
"comment" : "Hey, what's up?",
"created" : ISODate("2013-07-24T12:44:49.400Z"),
"productId" : ObjectId("51efcbd4786df13540e4688c"),
"userId" : ObjectId("51efcbc8786df13540e46887")
}
}
},
{
"_id" : ObjectId("51efcbd2786df13540e4688b"),
"value" : {
"UserDetails" : [
[
{
"country" : "CA",
"gender" : "M",
"age" : "18",
"userIdtemp" : ObjectId("51efcbc8786df13540e46887")
}
]
],
"comments" : {
"commentId" : ObjectId("51efcc43786df13540e46893"),
"comment" : "Cool",
"created" : ISODate("2013-07-24T12:44:51.004Z"),
"productId" : ObjectId("51efcbd2786df13540e4688b"),
"userId" : ObjectId("51efcbc8786df13540e46887")
}
}
},
{
"_id" : ObjectId("51efcbd4786df13540e4688c"),
"value" : {
"UserDetails" : [
[
{
"country" : "US",
"gender" : "M",
"age" : "25",
"userIdtemp" : ObjectId("51efcbc8786df13540e46888")
}
]
],
"comments" : {
"commentId" : ObjectId("51efcc41786df13540e46892"),
"comment" : "Not much",
"created" : ISODate("2013-07-24T12:44:49.475Z"),
"productId" : ObjectId("51efcbd4786df13540e4688c"),
"userId" : ObjectId("51efcbc8786df13540e46888")
}
}
}
],
"ok" : 1
}