Compare two nested objects and return an object with the keys which are into both of object - object

Let say that I have these two nested objects:
const sourceKeys = {
school: {
name: "Elisa Lemonnier",
students: 250
},
house: {
room : 2,
kids: true,
assets: "elevator",
}
}
const targetKeys = {
school: {
name: "Lucie Faure",
students: 150,
address: "123 Main St.",
phone: "555-555-5555"
},
house: {
room : 4,
kids: false,
assets: "Garden",
shop: "Auchan"
}
}
And I want the targetKeys keep ONLY the keys that are in sourceKeys. So I will get that :
const targetKeysMatchingSourceKeys = {
school: {
name: "Lucie Faure",
students: 150,
},
house: {
room : 4,
kids: false,
assets: "Garden",
}
}
I don't know how to proceed given that is a nested object. So, I will appreciate any help.
thanks you

I have find the solution, here is
const filteredJSON = Object.assign({}, TargetJsonToObject)
// Recursive function to filter the properties of the object
function filterObject(SourceJsonToObject, filteredObj) {
for (const key of Object.keys(filteredObj)) {
// If the key is not present in the source JSON, delete it from filtered JSON
if (!SourceJsonToObject.hasOwnProperty(key)) {
delete filteredObj[key]
} else if (typeof filteredObj[key] === "object") {
// If the key is present in the source JSON and the value is an object, recursively call the function on the nested object
filterObject(SourceJsonToObject[key], filteredObj[key])
}
}
}
filterObject(SourceJsonToObject, TargetJsonToObject)

Related

How to grab field value during a MongooseModel.bulkWrite operation?

Context:
I am trying to upsert in bulk an array of data, with an additional computed field: 'status'.
Status should be either :
- 'New' for newly inserted docs;
- 'Removed' for docs present in DB, but inexistent in incoming dataset;
- a percentage explaining the evolution for the field price, comparing the value in DB to the one in incoming dataset.
Implementations:
data.model.ts
import { Document, model, Model, models, Schema } from 'mongoose';
import { IPertinentData } from './site.model';
const dataSchema: Schema = new Schema({
sourceId: { type: String, required: true },
name: { type: String, required: true },
price: { type: Number, required: true },
reference: { type: String, required: true },
lastModified: { type: Date, required: true },
status: { type: Schema.Types.Mixed, required: true }
});
export interface IData extends IPertinentData, Document {}
export const Data: Model<IData> = models.Data || model<IData>('Data', dataSchema);
data.service.ts
import { Data, IPertinentData } from '../models';
export class DataService {
static async test() {
// await Data.deleteMany({});
const data = [
{
sourceId: 'Y',
reference: `y0`,
name: 'y0',
price: 30
},
{
sourceId: 'Y',
reference: 'y1',
name: 'y1',
price: 30
}
];
return Data.bulkWrite(
data.map(function(d) {
let status = '';
// #ts-ignore
console.log('price', this);
// #ts-ignore
if (!this.price) status = 'New';
// #ts-ignore
else if (this.price !== d.price) {
// #ts-ignore
status = (d.price - this.price) / this.price;
}
return {
updateOne: {
filter: { sourceId: d.sourceId, reference: d.reference },
update: {
$set: {
// Set percentage value when current price is greater/lower than new price
// Set status to nothing when new and current prices match
status,
name: d.name,
price: d.price
},
$currentDate: {
lastModified: true
}
},
upsert: true
}
};
}
)
);
}
}
... then in my backend controller, i just call it with some route :
try {
const results = await DataService.test();
return new HttpResponseOK(results);
} catch (error) {
return new HttpResponseInternalServerError(error);
}
Problem:
I've tried lot of implementation syntaxes, but all failed either because of type casting, and unsupported syntax like the $ symbol, and restrictions due to the aggregation...
I feel like the above solution might be closest to a working scenario but i'm missing a way to grab the value of the price field BEFORE the actual computation of status and the replacement with updated value.
Here the value of this is undefined while it is supposed to point to current document.
Questions:
Am i using correct Mongoose way for a bulk update ?
if yes, how to get the field value ?
Environment:
NodeJS 13.x
Mongoose 5.8.1
MongoDB 4.2.1
EUREKA !
Finally found a working syntax, pfeeeew...
...
return Data.bulkWrite(
data.map(d => ({
updateOne: {
filter: { sourceId: d.sourceId, reference: d.reference },
update: [
{
$set: {
lastModified: Date.now(),
name: d.name,
status: {
$switch: {
branches: [
// Set status to 'New' for newly inserted docs
{
case: { $eq: [{ $type: '$price' }, 'missing'] },
then: 'New'
},
// Set percentage value when current price is greater/lower than new price
{
case: { $ne: ['$price', d.price] },
then: {
$divide: [{ $subtract: [d.price, '$price'] }, '$price']
}
}
],
// Set status to nothing when new and current prices match
default: ''
}
}
}
},
{
$set: { price: d.price }
}
],
upsert: true
}
}))
);
...
Explanations:
Several problems were blocking me :
the '$field_value_to_check' instead of this.field with undefined 'this' ...
the syntax with $ symbol seems to work only within an aggregation update, using update: [] even if there is only one single $set inside ...
the first condition used for the inserted docs in the upsert process needs to check for the existence of the field price. Only the syntax with BSON $type worked...
Hope it helps other devs in same scenario.

Mongoose - Increment object counter when added to array

I'm trying to figure out what the most efficient way of doing this, preferably in one query. If I have an array...
[
{
name: "Eric",
priority: 1
{
[
If I append another object using $addToSet, how can I increment the counter? For example, if I add John...
[
{
name: "Eric",
priority: 1
},
{
name: "John",
priority: 2
{
]
I was thinking of something like this...
let room = await Room.findOneAndUpdate(
{ room_id: data.room_id },
{
$addToSet: {
guest_list: {
name: data.name
}
},
"guest_list.$.priority": guest_list.length
},
{ new: true }
);
I know this doesn't work, but it would be nice if I can get the length of the array and use that in the priority attribute as so...
"guest_list.$.priority": guest_list.length
What is the best way of doing this?

Add or push new object to nested mongodb document

I can't seem to find an answer to this on Stack or in the Mongoose docs. How do I added a new object into a nested document?
This is my current schema:
var SessionsSchema = mongoose.Schema({
session: {
sid: String,
dataloop: {
timeStamp: Date,
sensorValues:{
value: Number,
index: Number
}
}
}
});
Upon receiving new data from the client, I need to push into the existing session document, i've tried both $addToSet and $push but neither are giving me the correct results.
This is the $push:
Sessions.findOneAndUpdate(
{ 'session.sid': sessionID },
{
'$push:': {dataloop:{
timeStamp: datemilli,
sensorValues:{
value: pressure,
index: indexNum,
sessionTime: relativeTime
}
}
}
},
function(err,loop) {
console.log(loop);
}
)
Here is my expected output:
_id:58bb37a7e2950617355fab0d
session:Object
sid:8
dataloop:Object
timeStamp:2017-03-04 16:54:27.057
sensorValues:Object
value:134
index:18
sessionTime:0
dataloop:Object // <----------NEW OBJECT ADDED HERE
timeStamp:2017-03-04 16:54:27.059
sensorValues:Object
value:134
index:18
sessionTime:0
dataloop:Object // <----------ANOTHER NEW OBJECT
timeStamp:2017-03-04 16:54:27.059
sensorValues:Object
value:134
index:18
sessionTime:0
__v:0
If you consider to change your Schema to include a dataloop array :
var SessionsSchema = mongoose.Schema({
session: {
sid: String,
dataloop: [{
timeStamp: Date,
sensorValues: {
value: Number,
index: Number
}
}]
}
});
You could use $push on session.dataloop to add a new dataloop item :
Sessions.findOneAndUpdate({ 'session.sid': sessionID }, {
'$push': {
'session.dataloop': {
timeStamp: datemilli,
sensorValues: {
value: pressure,
index: indexNum,
sessionTime: relativeTime
}
}
}
},
function(err, loop) {
console.log(loop);
}
)

I am trying to get a single array value from mongodb, but when i try i get the whole object

1.I Don't get the Item in Electro Array but the whole doc
getItem(data){
dbswap.findOne(
{ 'swap.Items.Electro.id':data.id,
'swap.Items.Electro.id':data.id }, function(err,item){
if(err){
return (err);
}
if(item){
console.log(item);
}
});
} // EOF
This is my Schema
1.I am trying to get the item i create in Electro only, I don't want the whole object i am getting at the moment.
var swapSchema = new mongoose.Schema({
swap: {
name: String,
Items: {
Electro: [
{
name: String,
info: String,
price: Number,
dateCreated: Date,
category: String,
id: Number
}
]
}
}
});
Use the projection field :
If you want to get all the array :
dbswap.findOne(
{ 'swap.Items.Electro.id':data.id},
{ 'swap.Items.Electro' : 1}
, function(err, obj){
will return something like :
{
_id: ObjectId("sdfsdfsdf"),
Electro:[{....},{....}]
}
Or if you want only the object in the array who match the query :
dbswap.findOne(
{ 'swap.Items.Electro.id':data.id},
{ 'swap.Items.Electro.$' : 1}
, function(err, obj){
will return something like :
{
_id: ObjectId("sdfsdfsdf"),
Electro:{your match object}
}

How to scan through objects that are inside object. [JavaScript]

I am making a barcode scanner for my school project but i am stuck. I dont know how to scan through this object. I have this object with objects inside, and I need to scan through each object inside storage variable to check its barcode.
var storage = {
bolts: {
barcode: 57263144,
price: 0.5,
name: 'Plain Brackets',
stock: 25,
},
brackets: {
barcode: 13245627,
price: 0.2,
name: '100mm Bolts',
stock: 2,
},
}
I have a variable called barcode, and I need to test this variable if its the same like one of these. I tried using
for (var key in storage){
if (storage[key].barcode === barcode){
}
}
I would like the most simple way to do that.
Use Object.keys:
Object.keys(obj).forEach(function(key) {
console.log(key, obj[key]);
});
Below is the example:
var storage = {
"bolts": {
barcode: 57263144,
price: 0.5,
name: 'Plain Brackets',
stock: 25,
},
"brackets": {
barcode: 13245627,
price: 0.2,
name: '100mm Bolts',
stock: 2,
}
}
var barcode = 57263144;
Object.keys(storage).forEach(function(key) {
if(storage[key].barcode === barcode) { console.log("do something")}
});
A Fiddle:
https://jsfiddle.net/spechackers/34bhthza/
Use the recursive function to verify if exist more nodes in the objects, example:
const complexObj = {
name: "nobody",
address: { number: 22, moreNumbers: [1,2,3,4,5] },
colors: ["green", "red"],
numbersAgain: { first: 1, second: 4 }
};
function scanObj(obj){
for (let i in obj) {
/*
*Do some verificatio, example:
*I'd like to verify all numbers and if the numbers is greater than 3:
*/
if(typeof obj[i] == "number" && obj[i] > 3){ console.log(obj[i]); }
if (typeof obj[i] === "object") {
scanObj(obj[i])
}
}
}
//call the method
scanObj(complexObj);
Output: 22 4 5 4

Resources