Can Rails array be "unzipped"? - sql

I am using the following queries in a customer model call to obtain my desired set of transactions.
transactions = sub_account.transactions
transaction_items = transactions.map{|transaction| [transaction.transaction_items]}
However, this is returning an array of an array of hashes. From the rails console
[ [# <TransactionItem id: 29, amount: 20>, #<TransactionItem id: 35, amount: 40>],<br>
[# <TransactionItem id: 31, amount: 30>, #<TransactionItem id: 38, amount: 30>],<br>
[# <TransactionItem id: 43, amount: 30>, #<TransactionItem id: 21, amount: 40>],<br>
]
This process works well. But now I am trying to run a where query on transaction_items but can't becuase they're embedded in the array. Here is my final desired query that I am unable to run.
transaction_items.where(:amount => 30).sum("amount")
I know you can Zip an array, but can you unzip it? I can't find any documentation on it. If no unzip, can I adapt the where query to work on the embedded arrays?
Thanks.

What about:
transactions_items = []
transactions.each{|n|transactions_items = transactions_items.concat(n.transaction_items)}
Assuming that transactions.transactions_items is an array.
.each applies the block to each item, which concats the transactions_items of the current element n to the array transactions_items.
and
sum = 0
toSum = transactions_items.where(:amount => 30)
toSum.each{|transaction_item|sum += transaction_item.amount}
or
sum = 0
toSum = transactions_items.where(:amount => 30)
toSum.inject{|sum, transaction_item| sum + transaction_item.amount}
See How to sum array of numbers in Ruby?

Related

MongoDB - how to get last item within a two level hierarchy

My goal is to get the last stock quote from a database for each of the ticker symbols in the list.
I found the $last function, but not sure how to apply it to a level of a hierarchy, i.e. the per ticker symbol. (I just realized I only have need one level in the hierarchy now, but it would be nice to know how to do it for two als0. Per this doc page, the _id is supposed to be the group by expression, and I have set that to the ticker symbol.
(I'm using Python3 and PyMongo.)
This is the query I have now, but it is only returning one row. I want it to return 4 rows, one for each ticker.
tickerList = ['AAPL', 'MSFT', 'AMZN', 'NFLX']
docs = dbCollectionQuotes.aggregate([
{'$match': {
'$and': [
{'timestampYear': 2020},
{'timestampMonth': 10},
{'timestampDay': 6},
{'timestampHour': 15},
{'ticker': {'$in': tickerList }}
]
}},
{'$sort': {
'ticker': 1,
'timestampIsoDateTime': 1
}},
{'$group': {
'_id': '$ticker',
'lastId': {'$last': '$_id'},
'minuteClose': {'$last': '$minuteClose'},
'todaysChangePerc': {'$last': '$todaysChangePerc'},
'timestampIsoDateTime': {'$last': '$timestampIsoDateTime'}
}}
])

PyMongo Aggregation "AttributeError: 'dict' object has no attribute '_txn_read_preference'"

I'm sure there is an error in my code since I'm a newby to pyMongo, but I'll give it a go. The data in MongoDB is 167k+ and is as follows:
{'overall': 5.0,
'reviewText': {'ago': 1,
'buy': 2,
'daughter': 1,
'holiday': 1,
'love': 2,
'niece': 1,
'one': 2,
'still': 1,
'today': 1,
'use': 1,
'year': 1},
'reviewerName': 'dcrm'}
I would like to get a tally of terms used within that reviewText field for all 5.0 ratings. I have run the following code and I get the error that follows. Any insight?
#1 Find the top 20 most common words found in 1-star reviews.
aggr = [{"$unwind": "$reviewText"},
{"$group": { "_id": "$reviewText", "word_freq": {"$sum":1}}},
{"$sort": {"word_freq": -1}},
{"$limit": 20},
{"$project": {"overall":"$overall", "word_freq":1}}]
disk_use = { 'allowDiskUse': True }
findings = list(collection.aggregate(aggr, disk_use))
for item in findings:
p(item)
As you can see, I came across the 'allDiskUse' component since I seemed to exceed the 100MB threshold. But the error that I get is:
AttributeError: 'dict' object has no attribute '_txn_read_preference'
you are quite close, allowDiskUse is named parameter not a dictionary so the statement should be like this
findings = list(collection.aggregate(aggr, allowDiskUse=True))
or
findings = list(collection.aggregate(aggr, **disk_use ))
ManishSingh response is the best, but if you don't get exactly what he means and why you are having this error I can clarify what you have and why this is not correct:
The problem might be that you are using "allowDiskUse" with quotes like this:
findings = list(collection.aggregate(aggr, {"allowDiskUse": True})) # wrong
but the correct is this:
findings = list(collection.aggregate(aggr, allowDiskUse=True)) # correct

How to write a CASE clause with another column as a condition using knex.js

So my code is like one below:
.select('id','units',knex.raw('case when units > 0 then cost else 0 end'))
but it gives me error like this one
hint: "No operator matches the given name and argument type(s). You might need to add explicit type casts."
Any idea how I should right my code so I can use another column as an condition for different to column ?
I don't get the same error you do:
CASE types integer and character varying cannot be matched
but regardless, the issue is that you're trying to compare apples and oranges. Postgres is quite strict on column types, so attempting to put an integer 0 and a string (value of cost) in the same column does not result in an implicit cast.
Turning your output into a string does the trick:
.select(
"id",
"units",
db.raw("CASE WHEN units > 0 THEN cost ELSE '0' END AS cost")
)
Sample output:
[
{ id: 1, units: null, cost: '0' },
{ id: 2, units: 1.2, cost: '2.99' },
{ id: 3, units: 0.9, cost: '4.50' },
{ id: 4, units: 5, cost: '1.23' },
{ id: 5, units: 0, cost: '0' }
]

Multiple MySQL queries returning undefined when outputting value

I am running two database queries to retrieve data that I will outputting in a message embed. The queries are returning the proper rows when I just dump the entire result into the console. However, whenever I try to output the actual value for one of the rows, it displays as undefined in the message embed.
From what I've found based on examples, rows[0].somevalue should be outputting the correct results.
let mentionedUser = message.mentions.members.first();
let captainUser = client.users.find(user => user.id == `${mentionedUser.id}`);
con.query(`SELECT * FROM captains WHERE id = '${mentionedUser.id}';SELECT * FROM results WHERE captain = '${captainUser.username}'`, [2, 1], (err, rows) => {
if(err) throw err;
console.log(rows);
const infoEmbed = new Discord.RichEmbed()
.setColor("#1b56af")
.setAuthor('Captain Information', client.user.displayAvatarURL)
.setThumbnail('https://i.imgur.com/t3WuKqf.jpg')
.addField('Captain Name', `${mentionedUser}`, true)
.addField('Cap Space', `${rows[0].credits}`, true) // Returns undefined
message.channel.send(infoEmbed);
});
This is the console result
[ [ RowDataPacket {
id: '91580646270439424',
team_name: 'Resistance',
credits: 85,
roster_size: 2 } ],
[ RowDataPacket { id: 'Sniper0270', captain: 'BTW8892', credits: 10 },
RowDataPacket { id: 'Annex Chrispy', captain: 'BTW8892', credits: 5 } ] ]
In the code posted above, the expected output of rows[0].credits should output 85. No error codes are present, it just displayed as "undefined" in the message embed.
You are executing two queries inside a single query call. It looks like the mysql library returns an array of arrays in this scenario where the first value is the result of the first query and the second is the result of the second query. This is non standard. Normally you would either execute each query in its own query call or you would use a union to join the two queries into a single resultset.
this is not the practical way to send query request , as query is a single statement excluding the bulk update , you cannot execute two different query using a single con.query , it is not a proper way. execute them separately

Find entries with (certain) multiple tags

I have this query:
books = Book.includes(:tags).where(tags:{ id: [1, 2] })
The result contains all books having tags 1 OR 2. How can I change this to get only books which have both tags (1 AND 2)?
My approach was:
books = Book.includes(:tags).where(tags:{ id: 1 }).where(tags:{ id: 2 })
This went wrong, because the the second where overwrites the first one.
Not tested
books = Book.includes(:tags).where("tags:{ id: ? } AND tags:{ id: ?}", 1, 2)