add property to nested array in mongodb document - javascript

I have a mongodb document with the following structure
> db.user.find().limit(1);
{ "_id" : "1", "foo" : { "bars" : [
{
"name" : "bar1"
},
{
"name" : "bar2"
},
], ... }, ... }
I want to add a new property to each bar. I've got my script iterating over the bars array, but I can't get the new property in there, how can I do this?
var users = db.user.find({"foo.bars":{$exists:true}});
users.forEach(function(user) {
user.foo.bars.forEach(function(bar)
{
printjson(bar);
//how can I specify the current 'bar' in this update?
//db.experience.update({_id: user._id}, {$set: {"what goes here?" : "newbarValue"}});
});
});

So says the preacher man:
var users = db.user.find({"foo.bars":{$exists:true}});
users.forEach(function(user) {
var id = user._id;
var foo_bars = user.foo.bars;
var new_foo_bars = [];
for(var i = 0; i < foo_bars.length; i++) {
var foo_bar = foo_bars[i];
foo_bar['newkey'] = 'newvalue';
new_foo_bars.push(foo_bar);
}
db.user.update({"_id":id}, {$set:{"foo.bars":new_foo_bars}});
});

I have noticed that you are scrolling through the array on the client side there in JS.
If you were to form a new "bars" array from the old one then push it in as a whole new value this would mean you only do one DB call and the code is quite elegant.
If MongoDB does not support it normally it is better to just do the work on the client side.

You have to update each element of the nested document individually. Using the positional operator '$' will not work since it will only work on the first match (as documented).

Related

How to alter an item in an object using JavaScript to replace special characters that are not accepted by Firebase

I am trying to push some Kubernetes stats to my Firebase Real-time Database (not Firestore) and due to the special character "/" in the keys, Firebase is throwing an error. I tried to search for similar issues here but they are not quite similar to mine (tried so many replace or even delete functions but did not work). Here are my objects:
=====>> THE OBJECT
So i want to change the "/" to something like "-" on order to be able to push the entire object as to Firebase.
Example:
beta.kubernetes.io/arch --> beta.kubernetes.io-arch
beta.kubernetes.io/os --> beta.kubernetes.io-os
kubernetes.io/hostname --> kubernetes.io-hostname
node-role.kubernetes.io/master --> node-role.kubernetes.io-master
Please note that i have to process this in the attached object screenshot. So i have to process this: k8snodes{obj} -> items[arr] -> metadata{obj} -> labels{obj} in order to reach the keys i want to replace, and then push the entire object (k8snodes) to firebase.
I am using Javascript/NodeJS. thank you so much.
This is how you do it according to your data structure.
.reduce() reference: reduce
var k8snodes = {
items: [
{
"metadata": {
"labels": {
"beta.kubernetes.io/arch": "amd",
"beta.kubernetes.io/os": "linux"
}
}
},
{
"metadata": {
"labels": {
"kubernetes.io/hostname": "centos-master-node",
"node-role.kubernetes.io/master": "master"
}
}
}
]
}
k8snodes.items.forEach(function(data){
var newK8snodes = Object.keys(data.metadata.labels).reduce((total,currentValue) => {
var newLabelKey = currentValue.replace(/\//g,'-')
var newLabel = {[newLabelKey]: data.metadata.labels[currentValue]}
total = {...total, ...newLabel}
return total;
}, {});
data.metadata.labels = newK8snodes
});
console.log(k8snodes);
another simple solution is
var a = 'beta.kubernetes.io/arch';
console.log(a.replace('/','-'))
const ob = {
'beta.kubernetes.io/arch': 'amd',
'beta.kubernetes.io/os': 'linux',
'kubernetes.io/hostname': 'centos',
'node-role.kubernetes.io/master': 'master'
}
const newOb = {};
for(var i in ob) {
const newKey = i.replace(/\//g,'-')
newOb[newKey] = ob[i];
}
console.log(newOb);

Adding an Object to an Array

I'm struggling on adding an Object to an Array (E-commerce context).
My "tc_vars" datalayer is mapped with another datalayer which is called "wa_data". The latter sends the requested information to the first one.
An Object in that case will be a specific product and the Array will be the cart.content property :
var tc_vars = {
nav : {
siteCategory : wa_data.nav.siteCategory,
environment :wa_data.nav.environment,
siteType :wa_data.nav.siteType,
siteName :wa_data.nav.siteName,
pageName :wa_data.nav.pageName,
siteSection :wa_data.nav.siteSection,
country :wa_data.nav.country,
language :wa_data.nav.language,
template :wa_data.nav.template,
doNotTrack :window.navigator.doNotTrack,
customReferrer :wa_data.nav.customReferrer,
genomeID :wa_data.nav.genomeID,
mdmBID :wa_data.nav.mdmBID,
mdmIID :wa_data.nav.mdmIID
},
profile : {
uplayID : readCookie("user_id"),
loginStatus : ''
},
internalSearch : {
searchStatus :wa_data.internalSearch.searchStatus,
searchFilters :wa_data.internalSearch.searchFilters,
searchKeyWord :wa_data.internalSearch.searchKeyWord,
totalResults :wa_data.internalSearch.totalResults,
resultPosition :wa_data.internalSearch.resultPosition,
autoCompletion :wa_data.internalSearch.autoCompletion
},
product : {
productID :wa_data.product.productID,
unitSalePrice :wa_data.product.unitSalePrice,
salePrice :wa_data.product.salePrice,
stockAvailability :wa_data.product.stockAvailability,
salesType :wa_data.product.salesType,
costOfGood :wa_data.product.costOfGood
},
cart : {
orderID:wa_data.cart.orderID,
cartOpen:wa_data.cart.cartOpen,
cartAdd:wa_data.cart.cartAdd,
cartRemove:wa_data.cart.cartRemove,
cartView:wa_data.cart.cartView,
checkout:wa_data.cart.checkout,
purchase:wa_data.cart.purchase,
currency:wa_data.cart.currency,
paymentMethod:wa_data.cart.paymentMethod,
orderShipping:wa_data.cart.orderShipping,
orderTotalAmountDiscounted:wa_data.cart.orderTotalAmountDiscounted,
orderTotalAmountNotDiscounted:wa_data.cart.orderTotalAmountNotDiscounted,
orderTaxAmount:wa_data.cart.orderTaxAmount,
orderDiscountedAmount:wa_data.cart.orderDiscountedAmount,
orderShippingCost:wa_data.cart.orderShippingCost,
billingRegion:wa_data.cart.billingRegion,
billingCity:wa_data.cart.billingCity,
orderStatus:wa_data.cart.orderStatus,
content : [{
productID:'',
name:'',
quantity :'',
promoCode:'',
offerID:'',
salesType:'',
platform :'',
unitSalePrice:'',
salePrice:'',
stockAvailability:'',
lineItemTotalAmountDiscounted:'',
lineItemTotalAmountNotDiscounted:'',
lineItemTaxAmount:'',
lineItemDiscountedAmount:'',
lineItemShippingCost:'',
crossSell:'',
upSell:''
}]
},
tech : {
containerVersion : wa_data.tech.containerVersion
}
}
//Scanning for the content using a loop
if (typeof tc_vars.cart.content !== 'undefined' && tc_vars.nav.pageName === 'Basket'){
for(i=0; i < tc_vars.cart.content.length; i++) {
tc_vars.cart.content[i].productID = wa_data.cart.content[i].productID;
tc_vars.cart.content[i].name = wa_data.cart.content[i].name;
tc_vars.cart.content[i].quantity = wa_data.cart.content[i].quantity;
tc_vars.cart.content[i].promoCode = wa_data.cart.content[i].promoCode;
tc_vars.cart.content[i].offerID = wa_data.cart.content[i].offerID;
tc_vars.cart.content[i].salesType = wa_data.cart.content[i].salesType;
tc_vars.cart.content[i].platform = wa_data.cart.content[i].platform;
tc_vars.cart.content[i].unitSalePrice = wa_data.cart.content[i].unitSalePrice;
tc_vars.cart.content[i].salePrice = wa_data.cart.content[i].salePrice;
tc_vars.cart.content[i].stockAvailability = wa_data.cart.content[i].stockAvailability;
tc_vars.cart.content[i].lineItemTotalAmountDiscounted = wa_data.cart.content[i].lineItemTotalAmountDiscounted;
tc_vars.cart.content[i].lineItemTotalAmountNotDiscounted = wa_data.cart.content[i].lineItemTotalAmountNotDiscounted;
tc_vars.cart.content[i].lineItemTaxAmount = wa_data.cart.content[i].lineItemTaxAmount;
tc_vars.cart.content[i].lineItemDiscountedAmount = wa_data.cart.content[i].lineItemDiscountedAmount;
tc_vars.cart.content[i].lineItemShippingCost = wa_data.cart.content[i].lineItemShippingCost;
tc_vars.cart.content[i].crossSell = wa_data.cart.content[i].crossSell;
tc_vars.cart.content[i].upSell = wa_data.cart.content[i].upSell;
}
}
The problem I'm facing here is that my code is not creating a new object for each new product that is added to the cart content (with all the dedicated properties of the new object).
I've tried using a loop which scans my cart content Array but apparently it's not working (not adding a new object inside the Array). Seems like I'm missing something.
Do you guys have any ideas?
Thx a lot
J
tc_vars.cart.content[i] is undefined. You need to define it first, before filling it up.
for(i=0; i < tc_vars.cart.content.length; i++) {
tc_vars.cart.content[i] = {}; // Creates an empty object
tc_vars.cart.content[i].productID = wa_data.cart.content[i].productID; // Starts filling it
// ....
}
As an alternative (lighter syntax and faster execution), you could also write :
for(i=0; i < tc_vars.cart.content.length; i++) {
tc_vars.cart.content[i] = {
productID : wa_data.cart.content[i].productID,
name : wa_data.cart.content[i].name,
// ....
}
}
But we don't usually add things to an Array by its index. We just push things into it :
for(i=0; i < tc_vars.cart.content.length; i++) {
tc_vars.cart.content.push({
productID : wa_data.cart.content[i].productID,
name : wa_data.cart.content[i].name,
// ....
});
}
This being said, it looks like all you're doing here is copying (not instanciating) wa_data.cart.content into tc_vars.cart.content. So you can completely forget my answer and replace your whole for loop with Gurvinder's answer (+1'd him):
tc_vars.cart.content = JSON.parse(JSON.stringify(wa_data.cart.content));
Unless wa_data already have objects repeated at all the index, following code should work
tc_vars.cart.content = JSON.parse(JSON.stringify(wa_data.cart.content));
You can use an object literal:
tc_vars.cart.content[i] = {
productID: wa_data.cart.content[i].productID,
name: wa_data.cart.content[i].name,
quantity: wa_data.cart.content[i].quantity,
promoCode: wa_data.cart.content[i].promoCode,
offerID: wa_data.cart.content[i].offerID,
salesType: wa_data.cart.content[i].salesType,
platform: wa_data.cart.content[i].platform,
unitSalePrice: wa_data.cart.content[i].unitSalePrice,
salePrice: wa_data.cart.content[i].salePrice,
stockAvailability: wa_data.cart.content[i].stockAvailability,
lineItemTotalAmountDiscounted: wa_data.cart.content[i].lineItemTotalAmountDiscounted,
lineItemTotalAmountNotDiscounted: wa_data.cart.content[i].lineItemTotalAmountNotDiscounted,
lineItemTaxAmount: wa_data.cart.content[i].lineItemTaxAmount,
lineItemDiscountedAmount: wa_data.cart.content[i].lineItemDiscountedAmount,
lineItemShippingCost: wa_data.cart.content[i].lineItemShippingCost,
crossSell: wa_data.cart.content[i].crossSell,
upSell: wa_data.cart.content[i].upSell
}

javascript dynamic structure with array or object

Im trying to create a structure with Javascript as follows:
var users = {
user.id: {
session.id1: session.id1,
session.id2: session.id2,
session.id3: session.id3
},
user.id2: {
session.id1: session.id1,
session.id2: session.id2,
session.id3: session.id3
},
};
What i need: add new sessions and remove them, removing okay, but how should i define object and how can i push new sessions to user obejct? That's why key is equal to value.
If you want to use session.id1 instead of something like sessionId1 :
Assign value:
users['user.id'].['session.id1'] = value;
Create object:
var users = {
'user.id': {
'session.id1': session.id1,
'session.id2': session.id2,
'session.id3': session.id3
},
'user.id2': {
'session.id1': session.id1,
'session.id2': session.id2,
'session.id3': session.id3
},
};
But I don't recommend it. If you are the only one who is gonna work with this code, it's ok.
You can first create an empty object and fill it as and when the data comes like
users[user.id] = {};
For an example:
var users = {};
var user = {id : 1}; //Data received(Just an example)
users[user.id] = {};
var session = {id1 : 1.1}; //Data received
users[user.id][session.id1] = session.id1;
console.log(JSON.stringify(users));
How about refactoring the user object to store sessions as an array and push, pop and slice them as required.
var users = [
{
id:'userid',
sessions: [
{
id: 'sessionid',
sessiondata: something
},
{
id: 'sessionid',
sessiondata: something
}
]
}];
This way to can just use normal array operators on the session array for each user.

Couchdb join two documents using key

I have two documents one with tree structure and the other one relation to the first doc. Im trying to join these two doc`s by fk and pk. I couldnt get the actual results and it displays all null values.
First doc
{
"name": "one",
"root": {
"level1" : {
"level2" : {
"level3" : {
"itemone": "Randomkey1",
"itemtwo": "Randomkey2
}
}
}
},
"type": "firstdoc"
}
Second doc
{
"name" : "two",
"mapBy" : "Randomkey1",
"type" : "senconddoc
}
I`ve written a map function, which lists all the keys given a level 1 or 2 or 3 . Now I want o join this first doc and second doc using the key. Ive tried two ways (first: Im getting all (Root, Randomkey), (docName, Randomkey1) but it doesnt do any join. Im looking for a result like
(Root, docName)
Could someone assist in fixing this
map
function(doc) {
if (doc.type === 'firstdoc' || doc.type === 'seconddoc' ) {
var rootObj = doc.Root;
for (var level1 in rootObj) {
var level2Obj = doc.Root[level1];
for (var level2 in level2Obj) {
var keys = new Array();
var level3Obj = level2Obj[level2];
for (var i in level3Obj) {
var itemObj = level3Obj[i];
for (var i in itemObj) {
keys.push(itemObj[i]);
emit(doc.name, [itemObj[i], 0]);
var firstDocName = doc.name;
//This is gives null values
if (doc.Type === 'senconddoc' && doc.mapBy === itemObj[i]) {
emit(firstDocName , doc);
}
}
}
}
}
}
//This just lists keys to me
if (doc.type === 'senconddoc') {
emit([doc.mapBy, 1] , doc);
}
}
To simulate joins you have to output a doc with an _id in it, the value of the _id needs to point to an actual _id of a document. Then you can make use of include_docs=true to pull in the related documents. Example with many-to-many here: http://danielwertheim.se/couchdb-many-to-many-relations/
If this is not applicable, you can make a two step manual join by first returning custom keys. Then make a second query against the all documents view, with multiple keys specified.
It is much late but For such kind of tree structure, documents should be kept separately such as
{
id="firstDoc",
type="rootLevel"
}
{
id="secondDoc",
type="firstLevel"
parent="firstDoc"
}
{
id="thirdDoc",
type="firstLevel",
parent="firstDoc"
}
Now different levels can be joined using the Map Reduce function, Make sure that you will use it in proper way, Also use Logging so that you will be able to know in which sequence map/reduce function are being called by CouchDB.
Further, map Function should only be used for emitting the required document suppose if you want to to emit your level3 then in emit's value part, root.level1.level2.level3 should be there.
For more detail about the join you can refer
CouchDB Join using Views (map/reduce)

How to access elements inside nested objects in a Javascript loop using variable names?

I'm clueless. I have a JSON string like this which I need to check for a supplied "property" (postsome in the following example):
var index_file =
[{
"indexAB":[
{ "postsome": ["keyword_abc", "keyword_def"] },
{ "testsome": ["keyword_111", "keyword_222"] }
]
},{
"index_random": [
{ "postsome": ["keyword_abc"] }
]
}]
There my be any number of indices ("indexAB", "index_random") with n objects inside.
I need to "find" my property postsome but I cannot get it to work, because I'm struggling with the correct way of accessing the object.
So:
for (var i = 0, l = indices.length; i < l; i += 1) {
doc._id = "postsome",
index_name = "indexAB";
indices[i]["indexAB"]; // ok, returns object on correct iteration
indices[i][index_name]; // undefined
indices[i].indexAB[0][doc._id] // ok, returns undefined or keywords
indices[i][index_name][0][doc._id] // undefined
}
Question:
How can I access a nested object in loop using a variable name index_name?
This is not a direct answer to your question but I believe that it may actually help you more than giving you a complicated way to access values in your object.
If instead of this JSON object:
var index_file =
[{
"indexAB":[
{ "postsome": ["keyword_abc", "keyword_def"] },
{ "testsome": ["keyword_111", "keyword_222"] }
]
},{
"index_random": [
{ "postsome": ["keyword_abc"] }
]
}];
you would have this much simpler data structure:
var index_file =
{
"indexAB": {
"postsome": ["keyword_abc", "keyword_def"],
"testsome": ["keyword_111", "keyword_222"]
},
"index_random": {
"postsome": ["keyword_abc"]
}
};
then it would be much easier to access, using just:
var value = index_file.indexAB.postsome[0]; // no loops, no nothing
// value == "keyword_abc"
See: DEMO
I think that what you should change is your data model because currently it is something that is very far from the idea of JSON and it will always be very hard do access data in it.
A couple of issues
"indexAB" only exists on the first element in the array
you cannot have dots inside variable names.
I suggest you test whether indexAB is a property of the object before deferencing it further. See example below:
Fixed
var indices = index_file;
for (var i = 0, l = indices.length; i < l; i++) {
var doc_id = "postsome";
var index_name = "indexAB";
indices[i]["indexAB"]; // ok, returns object on correct iteration
indices[i][index_name]; // undefined
if ("indexAB" in indices[i]) {
indices[i].indexAB[0][doc_id] // ok, returns undefined or keywords
indices[i][index_name][0][doc_id] // undefined
}
}
index_name is undefined because the line prior to that raises an error
doc._id = "postname" // this causes an error
Just use a simple string
doc = "postname"

Categories