Below is my code. It works (yes!), but it requires 3 loops (yikes!). Still new to coding, but I am wondering if there is a more efficient, dryer, or simply better looking way of producing the desired result. The goal is to sum the values for all similar car makes. I then store the values in a hash for each make ({"Honda" => 12400}) and then store the hashes within an array. Not sure if this is the best way to go about it, but assume down the line you will want to access the values depending on the make. I also want to avoid hard coding anything - assume there are 100 different makes. All advice welcome!
cars = [
{
make: "Nissan",
model: "Model",
year: 2017,
value: 5000
},
{
make: "Toyota",
model: "Corolla",
year: 1997,
value: 1000
},
{
make: "Toyota",
model: "Camry",
year: 2006,
value: 3500
},
{
make: "Honda",
model: "Accord",
year: 2001,
value: 5000
},
{
make: "Toyota",
model: "Tacoma",
year: 2001,
value: 2000
},
{
make: "Honda",
model: "Civic",
year: 2001,
value: 1200
},
{
make: "Honda",
model: "Civic",
year: 2005,
value: 2200
},
{
make: "Honda",
model: "Accord",
year: 2010,
value: 4000
},
{
make: "Nissan",
model: "Altima",
year: 2017,
value: 10000
}
]
#GOAL
#Sum the values for all similar makes and store in an array with a nested hash
# sums_array = [{all_hondas: total_sum}, {all_toyotas: total_sum}]
total_value = 0
car_makes = []
cars.each{|car|
#creates a hash with a car's make as the key and 0 as the value
car_hash = {car[:make] => total_value}
#shovels car_hash into an array if it does not already exist within the array
unless car_makes.include? car_hash
car_makes << car_hash
end
}
values_array = []
car_makes.each {|make|
make.each {|k, v|
cars.each{|car|
if car[:make] == k
v += car[:value]
end
}
values_array << {k => v}
}
}
p values_array
#values_array = [{"Nissan"=>15000}, {"Toyota"=>6500},{"Honda"=>12400}]
Or in one iteration:
cars.each_with_object(Hash.new(0)) { |car, hash| hash[car[:make]] += car[:value] }
#=> {"Nissan"=>15000, "Toyota"=>6500, "Honda"=>12400}
Docs about Enumerable#each_with_object and Hash#new with a default
Related
I have 2 arrays of maps where one of them has product ids and quantities; and the other one has product ids, product names and price:
List<Map<String, dynamic>> arr1 = [
{ id: "1", name:"First Item", price: 10 },
{ id: "2", name: "Second Item", price: 12 }
];
List<Map<String, dynamic>> arr2 = [
{ id: "1", quantity: 1 },
{ id: "2", quantity: 3 },
{ id: "3", quantity: 2 }
];
Now I need to get total price of products by combining two arrays by obtaining sum of price * quantites.
I need an array similar to this:
List<Map<String, dynamic>> arr3 =[
{ id: "1", name:"First Item", price: 10, quantity: 1 },
{ id: "2", name: "Second Item", price: 12, quantity: 3 }
];
How can I merge them into one array based on their ids?
You can merge the array by mapping the first array to the second one.
final arr3 = arr1.map((product) {
final quantity = arr2
.where((quantities) => quantities["id"] == product["id"])
.map((quantities) => quantities["quantity"] as int)
.first;
return product..["quantity"] = quantity;
});
Full example: https://dartpad.dev/67148d132cb930bc6f1cee6a8a4fcff1
Hello members of stackoverflow, I'm totally new to mongoDB hence I'm having trouble with formulating some queries in it. I've been trying to do it for quite some time but have failed to do so. Please refer to the following code:
#create database
use db_m_1
#create collection (all tables in database)
db.createCollection('articles')
#this is your article in noSQL
#change this according to your info
article = {
_id: '1',
title: 'article1',
date_published: ISODate("2014-09-17T23:25:56.314Z"),
written_by: [{
_id: '1',
name: 'Osama'
}],
comments: [{
_id: '1',
content: 'This is very good article',
date: ISODate("2014-09-17T23:25:56.314Z"),
comment_by: {
_id: '1',
name: 'Osama'
password: 'pass'
}
}]
}
#this is used to insert
db.articles.insert(article)
#queries
#1-- know which comments were made on article 'a beginning' and by whom
#create query
let q1 = {
title: 'a beginning'
}
#create projection
db.articles.find(q1, {"Comments.username": 1, "Comments.comment_content": 1})
#2-- which staff members were working on article 'sample'
let q2 = {
title: 'sample'
}
let p2 = {
written_by: 1
}
db.articles.find(q2, p2);
#5-- which articles were written in 2014
let q5 = {
date_published: new Date("2014-10-01T00:00:00.000Z")}
}
q5 = {date_published: new Date("2014-05-13T00:00:00.000+00:00")}
let p5 = {
title: 1,
written_by: 1
}
I need help with query 3 and 4.
3-- how many articles has each staff member worked on?
4-- which staff members have worked on more than one article with maximum number of article writing staff on top
Thank you. :)
3-- how many articles has each staff member worked on?
4-- which staff members have worked on more than one article with
maximum number of article writing staff on top
These two aggregations solve the queries 3 and 4 respectively.
# 3
db.articles.aggregate( [
{
$unwind: "$written_by"
},
{
$group: {
_id: "$written_by.name",
count: { $sum: 1 }
}
},
{
$project: {
name: "$_id",
_id: 0,
count: 1
}
}
] )
# 4
db.articles.aggregate( [
{
$unwind: "$written_by"
},
{
$group: {
_id: "$written_by.name",
count: { $sum: 1 }
}
},
{
$match: {
count: { $gt: 1 }
}
},
{
$project: {
name: "$_id",
_id: 0,
count: 1
}
},
{
$sort: { count: -1 }
}
] )
Some test data:
article1 = {
_id: '1',
title: 'article1',
date_published: ISODate("2014-09-17T23:25:56.314Z"),
written_by: [ {
_id: '1',
name: 'Osama'
} ],
comments: [ {
_id: '1',
content: 'This is very good article',
date: ISODate("2014-09-17T23:25:56.314Z"),
comment_by: {
_id: '1',
name: 'Osama',
password: 'pass'
}
} ]
}
article2 = {
_id: '2',
title: 'article2',
written_by: [ {
_id: '9',
name: 'Krish'
},
{
_id: '1',
name: 'Osama'
} ],
comments: "..."
}
the data structure you use isn't proper for this kind of queries. I recommend you to have one collection per your entities, for this example we need 3 collections with these schema:
// article doc schema
{
_id: int,
title: String,
date_published: ISODate,
};
// writer doc schema
{
_id: int,
name: String,
articles_ids: [int]
};
// comment doc schema
{
_id: int,
content: String,
date: ISODate,
by_id: int,
article_id: int
};
by this way you can make complex queries, and you have to use aggregate query for your need. here is some examples:
// Query 03
// how many articles has each staff member worked on?
let piplines = [
{
// separate writers by their names
$group: {
_id: "$name",
totalArticles: { $size: "$articles_ids" }
}
}
];
let arrayOfStaffStates = writerCollection.aggregate(piplines);
// Query 04
// which staff members have worked on more than one article
let piplines = [
{
// separate writers by their names
$group: {
_id: "$name",
totalArticles: { $size: "$articles_ids" }
},
// match they who have more than 1 articles
$match: {
totalArticles: { $gte: 1 }
}
}
];
let stuffs = writerCollection.aggregate(piplines);
I have an array where each element in the array (representing a Supreme Court Chief Justice) contains an array of data points (the Chief Justice's name, number of disputes and year).
For each element in the top-level array, I need to sort the lower-level array in ascending order by year.
I attempted to sort year by ascending order using the following:
nested_data.forEach(function(d) {
d.values.sort(d3.ascending(d.values.year));
});
But it did not sort the lower-level array in ascending order by year.
Here is the console.log of my nested data to show its structure.
Array[5]
0:Object
key:"Vinson"
values:Array[7]
0:Object
chief:"Vinson"
disputes:142
year:Tue Jan 01 1946 00:00:00 GMT+0800 (CST)
1:Object
2:Object
3:Object
4:Object
5:Object
6:Object
1:Object
key:"Warren"
values:Array[16]
2:Object
key:"Burger"
values:Array[17]
3:Object
key:"Rehnquist"
values:Array[19]
4:Object
key:"Roberts"
values:Array[11]
How can I sort the lower-level array in ascending order by year?
This is the function:
nested_data.forEach(function(d) {
d.values.sort(function(a, b) {
return d3.ascending(+a.year, +b.year)
});
});
Your original function had two problems:
Since you're sorting the values arrays, you don't need to repeat values in the compareFunction
When specified, compareFunction uses two parameters, normally named a and b. You have to put d3.ascending inside compareFunction. Have a look here.
Here is a demo with a bogus data:
var data = [{
key: "foo",
values: [{
chief: "Bob",
year: 1982
}, {
chief: "Tom",
year: 1977
}, {
chief: "Carla",
year: 2010
}, {
chief: "Ana",
year: 1999
}]
}, {
key: "bar",
values: [{
chief: "Bill",
year: 2009
}, {
chief: "Ted",
year: 2014
}]
}, {
key: "baz",
values: [{
chief: "Fred",
year: 1998
}, {
chief: "Su",
year: 1992
}, {
chief: "Charlie",
year: 1999
}, {
chief: "Alice",
year: 1979
}]
}, ];
data.forEach(function(d) {
d.values.sort(function(a, b) {
return d3.ascending(+a.year, +b.year)
});
});
console.log(data);
<script src="https://d3js.org/d3.v4.min.js"></script>
I am new to mongodb. I am doing simple application that uses this database. Here is my doctors collection structure:
{
_id: 1,
name: "David",
specialisation: "dentist",
description: "Super dentist",
treatments: [
{
_id: 0,
price: 2200
},
{
_id: 2,
price: 200
},
{
_id: 5,
price: 2500
},
{
_id: 8,
price: 3200
},
{
_id: 13,
price: 2050
}
],
hospitals: [1, 2, 8, 5, 20]
},
{
_id: 2,
name: "John",
specialisation: "dentist",
description: "Super dentist",
treatments: [
{
_id: 2,
price: 2500
}
],
hospitals: [1]
}
What I want to do, is to get the max value of a treatment with specified id of all doctors in collection. For example in this case if I want to check treatment with _id = 2 it should return 2500, as it is written in John's object.
Any help would be appreciated. Thanks.
Named ur collection as stack
try this
db.stack.aggregate([ {$project:{"treatments._id":1, "treatments.price":1}},
{$unwind:"$treatments"},{$match:{"treatments._id":2}},
{$sort:{"treatments.price":-1}}, {$limit:1} ]);
result: { "_id" : 2, "treatments" : { "_id" : 2, "price" : 2500 } }
ref: https://docs.mongodb.org/manual/reference/operator/aggregation/unwind/
Lets say that I have the following document in the books collection:
{
_id:0 ,
item: "TBD",
stock: 0,
info: { publisher: "1111", pages: 430 },
tags: [ "technology", "computer" ],
ratings: [ { _id:id1, by: "ijk", rating: 4 }, {_id:id2 by: "lmn", rating: 5 } ],
reorder: false
}
I would like to update the value of ratings[k].rating and all I know is the id of the collection and the _id of the objects existing in the array ratings.
The tutorial of mongoDB has the following example that uses the position of the object inside the array but I suppose that if the update can only be done by knowing the position, this means that I firstly have to find the position and then proceed with the update? Can I do the update with only one call and if so how I can do that?
db.books.update(
{ _id: 1 },
{
$inc: { stock: 5 },
$set: {
item: "ABC123",
"info.publisher": "2222",
tags: [ "software" ],
"ratings.1": { by: "xyz", rating: 3 }
}
}
)
Sorry for late answer; I think this is what you want to do with mongoose.
Books.findOneAndUpdate({
_id: 1,
'ratings._id': id1
},
{
$set: {
'ratings.$.rating' : 3
}
}, function(err, book){
// Response
});
Positional operator may help you:
db.books.update(
// find book by `book_id` with `rating_id` specified
{ "_id": book_id, "ratings._id": rating_id },
// set new `value` for that rating
{ $set: { 'ratings.$.rating': value }}
);
$ will save position of matched document.