I'm trying to omit req.body data, when updating a resource in a collection, with only the fields that are null or '' for that existing resource in the collection.
But this could also be generic, that's why the title is more generic.
Anyways, imagine the following:
We have a user in our database with the following data:
{
"firstName": "John",
"lastName": "Doe",
"address": {
"Address1": "Random street 1",
"City": "",
"Country": null
},
"email": ""
}
The user is trying to update the existing resource with the following data:
{
"firstName": "Mark",
"address": {
"Address1": "Random street 2",
"City": "NY",
"Country": "USA"
},
"email": "john.doe#mail.com"
}
Updated object should like like this:
{
"firstName": "John", // Unchanged because propety value already exists
"lastName": "Doe",
"address": {
"Address1": "Random street 1", // Unchanged because propety value already exists
"City": "NY", // Updated because existing value is empty ("")
"Country": "USA" // Updated because existing value is null
},
"email": "john.doe#mail.com" // Updated because existing value is empty ("")
}
I'm using mongoose, but I would rather implement this on the basic javascript object level
I am not aware of any library but below is the working example using recursion.
var oldObj = {
"firstName": "John",
"lastName": "Doe",
"address": {
"Address1": "Random street 1",
"City": "",
"Country": null
},
"email": ""
}
var newObj = {
"firstName": "Mark",
"address": {
"Address1": "Random street 2",
"City": "NY",
"Country": "USA"
},
"email": "john.doe#mail.com"
}
updateObject(oldObj, newObj);
function updateObject(oldObj, newObj) {
Object.keys(oldObj).forEach( key => {
if (oldObj[key] && typeof oldObj[key] === 'object') {
updateObject(oldObj[key], newObj[key]);
} else {
oldObj[key] = oldObj[key] || newObj[key];
}
});
}
console.log("Modified Obj: ", oldObj);
Hope this may help you.
Related
I've a collection for user given below
{
"_id": 1
"firstname": "John"
"lastname": "Doe"
"address": {
"street": "13",
"city": "Los Angeles",
"state": "California",
"country": "USA",
"pincode": "12345"
}
}
I want to make an API that will update the user data.
This is what I've tried:
First Method
Using this method some fields are being removed from collection which are not present in request.
Query:
const updateUser = (userId, data) => {
return UserDB.updateOne({ _id: userId }, {
$set: {...data }
});
};
Request:
{
"_id": 1
"firstname": "Justin"
"lastname": "Thomas"
"address": {
"country": "Canada",
"pincode": "9999"
}
}
Result:
// street, city and state is removed from collection
{
"_id": 1
"firstname": "Justin"
"lastname": "Thomas"
"address": {
"country": "Canada",
"pincode": "9999"
}
}
Second Method:
Using this method, fields are set to null which are not present in the request.
Query:
const updateUser = (userId, data) => {
return UserDB.updateOne({ _id: userId }, {
$set: {
"firstname": data.firstname,
"lastname": data.lastname,
"address.street": data.address.street,
"address.city": data.address.city,
"address.state": data.address.state,
"address.country": data.address.country,
"address.pincode": data.address.pincode
}
});
};
Request:
{
"_id": 1
"firstname": "Justin"
"lastname": "Thomas"
"address": {
"country": "Canada",
"pincode": "9999"
}
}
Result:
// street, city and state is set to null in the collection.
{
"_id": 1
"firstname": "Justin"
"lastname": "Thomas"
"address": {
"street": null,
"city": null,
"state": null,
"country": "Canada",
"pincode": "9999"
}
}
Question
How can I update a nested object in a collection?
Second method is working fine playground, please check your data.
Use $addFields in aggregation pipeline of update operation.
$addFields will only update the values that is present in the object and other fields will remain as it is.
Like this:
db.collection.update({
_id: 1
},
[
{
$addFields: {
"firstname": "Justin",
"lastname": "Thomas",
"address": {
"country": "Canada",
"pincode": "16565"
}
}
}
])
Test it here: https://mongoplayground.net/p/pjO8mIKb03o
I have a sample object structure like below
Even though there are three types of addresses (address, employeeAddress, shippingAddress), they all represent the same data structure called address. From this object structure, I need to get all the addresses from the above structure.The object structure might be defined in using a JSON Schema format.
Also the addresses need not be always as part of the same hierarchy. For example in the above, shippingAddress and employeeAddress are at different hierarchy.
I tried with object's hasOwnProperty, but did not work the way as expected. Did not get much help from the filter method in lodash also. Is there an elegant way to achieve this?
{
"user": {
"firstName": "John",
"lastName": "Steve",
"address": {
"houseNo": "24",
"city": "CA",
"country": {
"code": "US",
"name": "United States"
}
}
},
"employee": {
"employeeID": "443434",
"employeeName": "Steve",
"employeeAddress": {
"houseNo": "244",
"city": "NJ",
"country": {
"code": "US",
"name": "United States"
}
}
},
"assistant": {
"assitantID": "443434",
"employeeName": "Steve",
"shippingDetails": {
"shippingAddress": {
"houseNo": "2444",
"city": "LA",
"country": {
"code": "US",
"name": "United States"
}
}
}
}
}
You could use recursion for this and create a function that takes input data and schema object. Then on each level another function checks if the current object matches schema structure.
const data = {"user":{"firstName":"John","lastName":"Steve","address":{"houseNo":"24","city":"CA","country":{"code":"US","name":"United States"}}},"employee":{"employeeID":"443434","employeeName":"Steve","employeeAddress":{"houseNo":"244","city":"NJ","country":{"code":"US","name":"United States"}}},"assistant":{"assitantID":"443434","employeeName":"Steve","shippingDetails":{"shippingAddress":{"houseNo":"2444","city":"LA","country":{"code":"US","name":"United States"}}}}}
const schema = {
houseNo: null,
country: null,
city: null
}
function match(o1, o2) {
return Object.keys(o1).every(k => k in o2);
}
function get(data, schema) {
return Object.keys(data).reduce((r, e) => {
if (match(data[e], schema)) r.push(data[e]);
else if (typeof data[e] == 'object') r.push(...get(data[e], schema));
return r;
}, [])
}
const result = get(data, schema);
console.log(result)
Here is a plain JS version of one found here
var user = { "user": { "firstName": "John", "lastName": "Steve", "address": { "houseNo": "24", "city": "CA", "country": { "code": "US", "name": "United States" } } }, "employee": { "employeeID": "443434", "employeeName": "Steve", "employeeAddress": { "houseNo": "244", "city": "NJ", "country": { "code": "US", "name": "United States" } } }, "assistant": { "assitantID": "443434", "employeeName": "Steve", "shippingDetails": { "shippingAddress": { "houseNo": "2444", "city": "LA", "country": { "code": "US", "name": "United States" } } } } }
function findProp(obj, prop) {
var result = {};
function recursivelyFindProp(o, keyToBeFound) {
Object.keys(o).forEach(function (key) {
if (typeof o[key] === 'object') {
if (key.toLowerCase().indexOf(keyToBeFound) !==-1) result[key]=o[key];
recursivelyFindProp(o[key], keyToBeFound);
} else {
if (key.toLowerCase().indexOf(keyToBeFound) !==-1) result[key]=o[key];
}
});
}
recursivelyFindProp(obj, prop);
return result;
}
console.log(
findProp(user, "address")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
Sample JSON Data:
{
"results": [
{
"name": "John Smith",
"state": "NY",
"phone": "555-555-1111"
},
{
"name": "Mary Jones",
"state": "PA",
"phone": "555-555-2222"
},
{
"name": "Edward Edwards",
"state": "NY",
"phone": "555-555-3333"
},
{
"name": "Abby Abberson",
"state": "RI",
"phone": "555-555-4444"
},
]}
With this sample data I can display individual values from the results [] array with object.name and object.phone to look something like:
John Smith 555-555-1111<br />
Mary Jones 555-555-2222<br />
Edward Edwards 555-555-3333<br />
Abby Abberson 555-555-4444
What I am trying to do now is select just the people who's state value is NY and only display their object.name and object.phone:
John Smith 555-555-1111<br />
Edward Edwards 555-555-3333
I tried this lovely little block but all it did was print all the names, which makes sense after I tried it.
if (object.state = "NY") {
div.append(repName);
}
I can't seem to think of a way to only display those that share a the same state.
I'm probably searching for the wrong terms or have to go about this another way... please help!
You are using =(assignment operator),which is wrong.
You have to use ==(comparison operator)
So do like below:-
if (object.state == "NY") {
div.append(repName);
}
Working sample-
var obj = {
"results": [
{
"name": "John Smith",
"state": "NY",
"phone": "555-555-1111"
},
{
"name": "Mary Jones",
"state": "PA",
"phone": "555-555-2222"
},
{
"name": "Edward Edwards",
"state": "NY",
"phone": "555-555-3333"
},
{
"name": "Abby Abberson",
"state": "RI",
"phone": "555-555-4444"
},
]};
$(obj.results).each(function(k,object){
if (object.state == "NY") {
$('#final_data').append(object.name +" : "+object.phone+"<br/>");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="final_data"></div>
My one cent solution:
var obj = {
"results": [
{
"name": "John Smith",
"state": "NY",
"phone": "555-555-1111"
},
{
"name": "Mary Jones",
"state": "PA",
"phone": "555-555-2222"
},
{
"name": "Edward Edwards",
"state": "NY",
"phone": "555-555-3333"
},
{
"name": "Abby Abberson",
"state": "RI",
"phone": "555-555-4444"
},
]};
obj.results.forEach((value) => {
if (value.state === "NY") {
const li = document.createElement("li");
li.innerHTML = `${value.name} : ${value.phone}`;
document.querySelector("#final_data").appendChild(li);
}
});
<ul id="final_data"></ul>
Like Alive said you used the assignment operator = instead of comparison operator === or ==.
Hi I have an object which has only one property as "contacts" and its value is an array which contains 4 objects and each object has properties like email, firstname etc...
I want to remove a particular object from that array by matching its email property with an given email.
I am trying to iterate through that array using $.each loop in jQuery and trying to match email in each iteration and when matched I am trying to delete that object using splice but it is not working.
Below is a sample code similar to what I am implementing:
//main object with all the data
var data = {
"contacts": [
{
"email": "jonas.sultani#hellyhansen.com",
"firstname": "Jonas",
"lastname": "Sultani",
"prefix": "Mr",
"title": "Consultant",
"company": "Helly Hansen",
"phone": "+49 6245 99334",
"fax": "+49 6245 99335"
},
{
"email": "james.simmons#boeing.com",
"firstname": "James H",
"lastname": "Simmons",
"prefix": "Mr",
"title": "AP Lead",
"company": "Boeing",
"phone": "+1 112-445-6684",
"fax": ""
},
{
"email": "slmarino#boehringer-ingelheim.com",
"firstname": "Stephanie",
"lastname": "Marino",
"prefix": "Mrs",
"title": "Project Manager",
"company": "Boehringer Ingelheim",
"phone": "+1 650-554-5124",
"fax": ""
}
]
}
//extracting array from the data object
var myArray = data.contacts;
//sample email to match and delete the object
var email = "jonas.sultani#hellyhansen.com";
//function to delete the object containing the passed email
function deleteElement(myId){
//iterating the myArray to check the email with the given email
$.each(myArray, function(key, val){
var email = val.email;
//if the email is matched the particular object on the current index in the array is deleted using splice
if(myId === email){
myArray.splice(key,1);
return;
}
});
}
//calling the function and passing the email to delete the object
deleteElement(email);
//printing the modified array
console.log(myArray);
This method is not working so can you please let me know how can I make this work.
Note: I don't want to modify anything with the data object or myArray but I want to find solution with the current situation
Big Thanks
I would advise against the use of jQuery (because you don't need it) and against any for/while loop, and just KISS it :
function deleteElementWithEmail(data, email) {
return data.filter(function (current) {
return current.email !== email
})
}
With all your code:
//main object with all the data
var data = {
"contacts": [
{
"email": "jonas.sultani#hellyhansen.com",
"firstname": "Jonas",
"lastname": "Sultani",
"prefix": "Mr",
"title": "Consultant",
"company": "Helly Hansen",
"phone": "+49 6245 99334",
"fax": "+49 6245 99335"
},
{
"email": "james.simmons#boeing.com",
"firstname": "James H",
"lastname": "Simmons",
"prefix": "Mr",
"title": "AP Lead",
"company": "Boeing",
"phone": "+1 112-445-6684",
"fax": ""
},
{
"email": "slmarino#boehringer-ingelheim.com",
"firstname": "Stephanie",
"lastname": "Marino",
"prefix": "Mrs",
"title": "Project Manager",
"company": "Boehringer Ingelheim",
"phone": "+1 650-554-5124",
"fax": ""
}
]
}
//extracting array from the data object
var myArray = data.contacts;
//sample email to match and delete the object
var email = "jonas.sultani#hellyhansen.com";
//function to delete the object containing the passed email
function deleteElementWithEmail(data, email) {
return data.filter(function (current) {
return current.email !== email
})
}
//calling the function and passing the email to delete the object
myArray = deleteElementWithEmail(myArray, email);
//printing the modified array
console.log(myArray);
Use a do..while loop or while loop to remove elements from an array within a loop
let i = 0;
let len = data.contacts.length;
do {
var email = data.contact[i].email;
if (myId === email) {
data.contacts.splice(i, 1);
break;
}
++i;
} while (i < len);
You can use array.filter function to get desired result.
//main object with all the data
var data = {
"contacts": [{
"email": "jonas.sultani#hellyhansen.com",
"firstname": "Jonas",
"lastname": "Sultani",
"prefix": "Mr",
"title": "Consultant",
"company": "Helly Hansen",
"phone": "+49 6245 99334",
"fax": "+49 6245 99335"
},
{
"email": "james.simmons#boeing.com",
"firstname": "James H",
"lastname": "Simmons",
"prefix": "Mr",
"title": "AP Lead",
"company": "Boeing",
"phone": "+1 112-445-6684",
"fax": ""
},
{
"email": "slmarino#boehringer-ingelheim.com",
"firstname": "Stephanie",
"lastname": "Marino",
"prefix": "Mrs",
"title": "Project Manager",
"company": "Boehringer Ingelheim",
"phone": "+1 650-554-5124",
"fax": ""
}
]
}
//extracting array from the data object
var myArray = data.contacts;
//console.log(myArray);
//sample email to match and delete the object
var email = "jonas.sultani#hellyhansen.com";
//function to delete the object containing the passed email
function deleteElement(myId) {
myArray = myArray.filter(function(el) {
return el.email != myId;
});
}
//calling the function and passing the email to delete the object
deleteElement(email);
//printing the modified array
console.log(myArray);
function main(message){
...
phone= JSON.parse(message.phoneNumbers);
... }
My input JSON is
{
"firstName": "John",
"lastName": "Smith",
"isAlive": true,
"age": 25,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
},
{
"type": "mobile",
"number": "123 456-7890"
}
],
"children": [],
"spouse": null
}
The result I receive is omitting the "phoneNumbers" but I do want it.
Your data is correct, when i JSON.parse it, i get everything allright.
But you don't seem to access to your data in the right way. You must first parse the whole JSON, then you have a javascript object, and only then you can acces your property.
in detail:
var obj = JSON.parse(message);
var phone = obj.phoneNumbers;
or in short:
var phone = (JSON.parse(message)).phoneNumbers;