I have a Schema
{
name: {type:String}
.....
child : {type: [childSchema], []}
}
and A child schema
{
x:{type:Number}
y:{type:Number},
options: {type:Array, default}
}
The problem is while I can update an individual children properties with a particular child id, I cannot update/replace the Options array (just an array of strings), I have
parent.findOneAndUpdate({
_id: id,
status: 'draft',
child: {
$elemMatch: {
_id: childId
}
}
}, {
$set: {
child.$.x : newX,
child.$.y : newy,
child.$.options : ['option1', 'option2']
}
}).lean().exec()
I have also tried
$set: {
'child.$.x' : newX,
'child.$.y' : newy,
'child.$.options' : { '$all' ['option1', 'option2']}
}
I think (but I am unsure) that maybe I cannot use any of the $ functions ($set, $all) at this level
When I google I seem to find more links about updating subdocument and can find anything on replacing an array in a subdocument, tried looking in the Mongodb & mongoose API but Unless I am overlooking something I can't find anything that would work in this case
can anyone point me in the right direction
Try an update like in the following example from the mongo shell:
> db.test.drop()
> db.test.insert({
"_id" : 0,
"children" : [
{ "_id" : 1, "x" : 1, "y" : 2, "options" : [1, 2, 3] },
{ "_id" : 2, "x" : 5, "y" : 8, "options" : [1, 6, 2] }
]
})
> db.test.update({ "_id" : 0, "children._id" : 1 },
{ "$set" : { "children.$.x" : 55, "children.$.y" : 22, "children.$.options" : [9, 8, 7] } }
)
> db.test.findOne()
{
"_id" : 0,
"children" : [
{ "_id" : 1, "x" : 55, "y" : 22, "options" : [9, 8, 7] },
{ "_id" : 2, "x" : 5, "y" : 8, "options" : [1, 6, 2] }
]
}
Related
I have an array of grouped objects, but I'm unable to iterate through and achieve the desired result.
[ 000000010: [
{
"userId" : "000000010",
"played" : 10,
"lost" : 5,
"date" :"2019-04-01T00:00:00.000Z"
},
{
"userId" : "000000010",
"played": 15,
"lost" : 0,
"date" :"2019-04-02T00:00:00.000Z"
},
],
000000020: [
{
"userId" : "000000020",
"played": 11,
"lost" : 4,
"date" :"2019-04-01T00:00:00.000Z"
},
{
"userId" : "000000020",
"played": 15,
"lost" : 0,
"date" :"2019-04-02T00:00:00.000Z"
},
]
]
I want to eliminate all possible duplicates and group all similar objects as follows
{
"userId" : "000000010",
"played": 30,
"lost" : 5,
},
{
"userId" : "000000020",
"played": 26,
"lost" : 6,
},
I have tried
Object.entries()
but it returned
[obeject: object]
I have also tried
const allResults = {}
Object.keys(result).forEach(function(key) {
let chats = result[key].chats;
allResults[chats] = allResults[chats] ? allResults[chats] + 1 : 1;
});
But I get undefined
If you are looking to sum the played and lost fields you should use reduce to merge the objects, summing the required fields. Then convert the array of entries back into an object.
Try this
const inputData = {
"000000010":[
{
"userId":"000000010",
"played":10,
"lost":5,
"date":"2019-04-01T00:00:00.000Z"
},
{
"userId":"000000010",
"played":15,
"lost":0,
"date":"2019-04-02T00:00:00.000Z"
}
],
"000000020":[
{
"userId":"000000020",
"played":11,
"lost":4,
"date":"2019-04-01T00:00:00.000Z"
},
{
"userId":"000000020",
"played":15,
"lost":0,
"date":"2019-04-02T00:00:00.000Z"
}
]
};
const result = Object.entries(inputData).map(([key, values]) => {
const merged = values.reduce((accum, x) => {
accum.played += x.played;
accum.lost += x.lost;
return accum;
}, {"userId": key, "played": 0, "lost": 0});
return [key, merged];
});
console.log(Object.fromEntries(result));
Node prints the following
{
'000000010': { userId: '000000010', played: 25, lost: 5 },
'000000020': { userId: '000000020', played: 26, lost: 4 }
}
I have corrected the json data format and made this code. The following code does not delete the the key date. Please do tell me if this works for you.
function removeDuplicates() {
// Create an array of objects
var movies = [{
"000000010": [{
"userId": "000000010",
"played": 10,
"lost": 5,
"date": "2019-04-01T00:00:00.000Z"
},
{
"userId": "000000010",
"played": 15,
"lost": 0,
"date": "2019-04-02T00:00:00.000Z"
},
]
},
{
"000000020": [{
"userId": "000000020",
"played": 11,
"lost": 4,
"date": "2019-04-01T00:00:00.000Z"
},
{
"userId": "000000020",
"played": 15,
"lost": 0,
"date": "2019-04-02T00:00:00.000Z"
},
]
}
];
jsonObject = movies.map(JSON.stringify);
uniqueSet = new Set(jsonObject);
uniqueArray = Array.from(uniqueSet).map(JSON.parse);
console.log(uniqueArray);
}
<p>
Click on the button to remove the duplicated in the array
</p>
<p>Check the console for the output</p>
<button onclick="removeDuplicates();">
Click here
</button>
Say I have a dictionary with nested sub-dictionaries:
let dict =
{
"SEATTLE" : {
"gross_sales" : 106766,
"price" : 584.50,
"dates" : [ {
"date" : "2020-03-13",
"total_sales_to_date" : 2,
"new_sales" : 2,
}
, {
"date" : "2020-03-19",
"total_sales_to_date" : 5,
"new_sales" : 3,
}
]
}
,
"PHOENIX" : {
"gross_sales" : 26691.5,
"price" : 292.25,
"dates" : [ {
"date" : "2020-03-13",
"total_sales_to_date" : 9,
"new_sales" : 9,
}
, {
"date" : "2020-03-19",
"total_sales_to_date" : 19,
"new_sales" : 10,
}
]
}
}
And I would like to normalise each numerical value in the key/value pairs against the other key/values and then append these as new key/value pairs.
For the dates array of time-series data I'd like to normalise each key/value pair in each date against both time (within the array) and against the other locations on the same date (other objects).
For example, this is what I'm seeking after the operation:
{
"SEATTLE" : {
"gross_sales" : 106766,
"normalised_gross_sales" : 1.0,
"price" : 584.50,
"normalised_price" : 1.0,
"dates" : [ {
"date" : "2020-03-13",
"total_sales_to_date" : 2,
"norm_total_sales_over_time" : 0.4,
"norm_total_sales_over_locations" : 0.22222222,
"new_sales" : 2,
}
, {
"date" : "2020-03-19",
"total_sales_to_date" : 5,
"norm_total_sales_over_time" : 1.0,
"norm_total_sales_over_locations" : 0.26315789,
"new_sales" : 3,
}
]
}
,
"PHOENIX" : {
"gross_sales" : 26691.5,
"normalised_gross_sales" : 0.25,
"price" : 292.25,
"normalised_price" : 0.5,
"dates" : [ {
"date" : "2020-03-13",
"total_sales_to_date" : 9,
"norm_total_sales_over_time" : 0.47368421,
"norm_total_sales_over_locations" : 1.0,
"new_sales" : 9,
}
, {
"date" : "2020-03-19",
"total_sales_to_date" : 19,
"norm_total_sales_over_time" : 1.0,
"norm_total_sales_over_locations" : 1.0,
"new_sales" : 10,
}
]
}
}
ie: the total_sales_to_date value for the last date in the array should normalise to 1.0 as norm_total_sales_over_time
and the largest total_sales_to_date value for all objects (SEATTLE, PHOENIX) for the current date in the array should normalise to 1.0 as norm_total_sales_over_locations
I'm finding this very complex to handle in JS. My actual task involves dictionaries with hundreds of sub-dictionaries I need to compare, I'm looking for a scalable solution. In a pandas dataframe this would be trivial, however I'd like to learn how to approach this using modern javascript only as I'm running this process from node.js using an ES6 interpreter.
What is an effective ES6 javascript solution to this?
Here is a solution that returns the normalised values in the manner described:
let dict = {
"SEATTLE": {
"gross_sales": 106766,
"price": 584.50,
"dates": [{
"date": "2020-03-13",
"total_sales_to_date": 2,
"new_sales": 2,
}, {
"date": "2020-03-19",
"total_sales_to_date": 5,
"new_sales": 3,
}]
},
"PHOENIX": {
"gross_sales": 26691.5,
"price": 292.25,
"dates": [{
"date": "2020-03-13",
"total_sales_to_date": 9,
"new_sales": 9,
}, {
"date": "2020-03-19",
"total_sales_to_date": 19,
"new_sales": 10,
}]
}
}
async function normaliseDict(_dict) {
let values = await Object.values(_dict);
// make arrays with values from each key
let all_gross_sales = [];
let all_price = [];
let all_total_sales = {};
values.forEach((element) => {
all_gross_sales.push(element.gross_sales);
all_price.push(element.price);
let most_recent_total_sales_value = element.dates[element.dates.length - 1].total_sales_to_date;
element.dates.forEach((date, idx) => {
date.norm_total_sales_over_time = date.total_sales_to_date / most_recent_total_sales_value;
if (all_total_sales[date.date]) all_total_sales[date.date].push(date.total_sales_to_date);
else {
all_total_sales[date.date] = [];
all_total_sales[date.date].push(date.total_sales_to_date);
}
});
});
const newDict = values.map(ob => {
ob.gross_sales_norm = ob.gross_sales / Math.max(...all_gross_sales);
ob.price_norm = ob.price / Math.max(...all_price);
return ob;
});
values.forEach((element) => {
element.dates.forEach((date, idx) => {
date.norm_total_sales_over_locations_for_this_date = date.total_sales_to_date / Math.max(...all_total_sales[date.date]);
});
});
return await dict;
}
(async () => {
console.log(await normaliseDict(dict))
})()
I have a object.
var dl_items;
After a loop for inputing data:
dl_items[code] = itemObject;
I have a array:
dl_items : {
"code_A" : { "index" : 1, "status" : 2, "name" : A_data},
"code_B" : { "index" : 2, "status" : 0, "name" : B_data},
"code_C" : { "index" : 3, "status" : 1, "name" : C_data},
"code_D" : { "index" : 4, "status" : 2, "name" : D_data},
"code_E" : { "index" : 5, "status" : 4, "name" : E_data}
}
Now I want to remove "dl_items[code_D]" and insert it into after "code_A" (index 2) for result like :
dl_items : {
"code_A" : { "index" : 1, "status" : 2, "name" : A_data},
"code_D" : { "index" : 4, "status" : 2, "name" : D_data},
"code_B" : { "index" : 2, "status" : 0, "name" : B_data},
"code_C" : { "index" : 3, "status" : 1, "name" : C_data},
"code_E" : { "index" : 5, "status" : 4, "name" : E_data}
}
I try to use "delete" after using a loop to find index of code_D:
delete dl_items[code_D];
and it successful removed but how can i insert code_D into his new index ?
Edit : Thanks all everyone to help me understand more about array.
Since object doesn't have an order, you need to convert your current implementation into array:
var dl_items = [];
When you need to add an item to the array:
dl_items.push({ code: code, item: itemObject });
Now, the similar data as array from your question is:
dl_items: [
{ code :"code_A", item: { index: 1, status: 2, name: "A_data" } },
{ code :"code_B", item: { index: 2, status: 0, name: "B_data" } },
{ code :"code_C", item: { index: 3, status: 1, name: "C_data" } },
{ code :"code_D", item: { index: 4, status: 2, name: "D_data" } },
{ code :"code_E", item: { index: 5, status: 3, name: "E_data" } },
]
In order to move the entry with code_D after the entry with code_A, use the following:
var codeDEntry = dl_items[3];
dl_items = dl_items
.filter(function(entry) {
return entry !== codeDEntry;
})
.splice(1, 0, codeDEntry);
Hope this helps!
You can make a temp var like this :
tempItem = dl_items.code_D;
dl_items.code_D = dl_items.code_B;
dl_items.code_B = tempItem;
What you have here is an object, not an array. Therefore, there is no concept of an index here.
You can map your object keys into an array as follows:
let array = Object.keys(dl_items);
You can then reorder their positions.
I need your help for a little algorithme for my app :
i have an object like this :
var obj = { "response" : [
"candidate" : {
"id":"1",
"price" : 10,
"distance" : 20
},
"candidate" : {
"id":"2"
"price" : 14,
"distance" : 2
},
"candidate" : {
"id":"3",
"price" : 200,
"distance" : 1
}
] }
Which i sort by price like this :
var sortPrice = _(obj.response).sortBy(function(p){
return p.candidate.price
})
It works fine and sort the object (ids) : 1,2,3
Now if candidate has the same price but different distance, i should show first candidate with the same price and the lowest distance :
var obj = { "response" : [
"candidate" : {
"id":"1",
"price" : 10,
"distance" : 20
},
"candidate" : {
"id":"2"
"price" : 10,
"distance" : 2
},
"candidate" : {
"id":"3",
"price" : 200,
"distance" : 1
}
] }
var sorted = _(obj.response).chain().sortBy(function (p) {
return parseInt(p.candidate.price) ;
}).sortBy(function(d){
return parseInt(d.candidate.distance)
}).value();
But it sort me the lowest distance first (ids) : 3(with distance 1), 2(with distance 2), 1(with distance 20) than 2,1,3
Do you have any suggestion?
Thank you.
In pure js you can use sort() like this.
var obj = {
"response": [{
"candidate": {
"id": "1",
"price": 8,
"distance": 20
}
}, {
"candidate": {
"id": "2",
"price": 8,
"distance": 2
}
}, {
"candidate": {
"id": "3",
"price": 200,
"distance": 1
}
}]
}
obj.response.sort(function(a, b) {
return a.candidate.price - b.candidate.price || a.candidate.distance - b.candidate.distance;
})
console.log(obj.response)
Lodash is a fork of underscore that allows you to sort by several properties of the object.
Using it, a solution could be:
_(obj.response).map(_.partial(_.get, _, 'candidate')).sortBy(['price', 'distance']).value();
Here's the fiddle in case you want to play with it.
I've been trying to use the MapReduce functionaltity in Mongo 2.6.11 to help in returning an array of objects as a value to a corresponding key.
For example, given the following input to a MapReduce job:
{ IncidentNumber : 123, StartLoc : 5, EndLoc : 10, },
{ IncidentNumber : 123, StartLoc : 10, EndLoc : 15, },
{ IncidentNumber : 123, SStartLoc : 10, EndLoc : 15, },
{ IncidentNumber : 321, StartLoc : 0, EndLoc : 5, },
{ IncidentNumber : 321, StartLoc : 10, EndLoc : 20, }
I would like to get output that looks like this:
{ IncidentNumber : 123, Locations : [{StartLoc : 5, EndLoc : 10},{StartLoc : 10, EndLoc : 15}, {StartLoc : 10, EndLoc : 15}],
{ IncidentNumber : 321, Locations : [{StartLoc : 0, EndLoc : 5},{StartLoc : 10, EndLoc : 20}]
My current map and reduce functions for this is as follows:
var mapFunction = function() {
emit(this.IncidentNumber, {StartLoc : this.StartLoc, EndLoc: this.EndLoc} )
}
var reduceFunction = function(key, values) {
var out = []
return out.push(values);
}
This is giving me results that look like:
{ "_id" : 50144, "value" : 1 }
{ "_id" : 68971, "value" : { "startLoc" : 10, "endLoc" : 5} }
{ "_id" : 108294, "value" : 1 }
{ "_id" : 165130, "value" : 1 }
{ "_id" : 194016, "value" : 1 }
{ "_id" : 210018, "value" : 1 }
{ "_id" : 210195, "value" : 1 }
{ "_id" : 212069, "value" : 1 }
I know my reduce function is not correct and I'm not sure if this is an odd use case as I'm not really doing any actual 'reduction'. But I'm not sure exactly what the problem is. Any help would be much appreciated.
Thanks.
After some more searching I found a way of a getting this to work based on this post MongoDB Map/Reduce Array aggregation question. For anyone who is trying to solve the same problem The map/reduce functions I've used are as follows:
var mapFunction = function() {
emit( {
incident: this.IncidentNumber,
} , {
data: [ { start : this.startLoc, end : this.endLoc} ]
} );
}
var reduceFunction = function(key,values) {
var out = [];
values.forEach(function(d){
Array.prototype.push.apply(out, d.data);
});
return { data: out };
}