datomic pull api pattern to exclude ident - datomic

I have a schema like this:
:user/first-name
:user/last-name
:user/password
:user/groups
;; assume there are x more ident
:user/email
I'm pulling this by doing:
(d/pull db '[*] some-id)
Apparently this will also pull :user/password which I don't want, and doing this is cumbersome:
(d/pull db
[:user/first-name :user/last-name ;; all fields except :user/password]
some-id)
Is there anyway to do something like this:
(d/pull db ['* (except :user/password)] some-id)

You can use datomic's filter function to filter out datoms you don't need from db value.
In your case something like
(d/pull (filter db #(not (= (second %2) :user/password))) some-id)

Related

How do you update a single value in xtdb?

Given the following document
{:xt/id 1
:line-item/quantity 23
:line-item/item 20
:line-item/description "Item line description"}
I want to update the quantity to 25
As I can tell so far, I will need to first query the DB, get the full doc, merge in the change, then transact the new doc back.
Is there a way to merge in just a change in quantity without doing the above?
Thank you
You should be able to use transaction functions for this. These will allow you to specify those multiple steps and push them down into the transaction log to ensure that they execute in-sequence (i.e. that you will always retrieve the latest doc to update against at the point in time the transaction function call itself is pushed into the transaction log).
For your specific example I think it would look something like this (untested):
(xt/submit-tx node [[::xt/put
{:xt/id :update-quantity
;; note that the function body is quoted.
;; and function calls are fully qualified
:xt/fn '(fn [ctx eid new-quantity]
(let [db (xtdb.api/db ctx)
entity (xtdb.api/entity db eid)]
[[::xt/put (assoc entity :line-item/quantity new-quantity)]]))}]])
This creates the transaction function itself, then you just need to call it to make the change:
;; `[[::xt/fn <id-of-fn> <id-of-entity> <new-quantity>]]` -- the `ctx` is automatically-injected
(xt/submit-tx node [[::xt/fn :update-quantity 1 25]])

How to save array in database correctly?

I want to add array in database. I use ruby, sequel and postgresql, but question about true way, and not program realization.
I see 3 path:
Use special adapters. It help to save array like [1,2,3,4] in db after some changes: in database it will look like "{1,2,3,4}". BUT after it I don't know how to convert this entry back to [1,2,3,4] without bullshits.
Convert array to json and save it to database. Array like [1,2,3,4] will be look like "[1,2,3,4]". And I can easy convert back by JSON.parse.
Convert array by Marshal and save. Array [1,2,3,4] will be look like "\x04\b[\ti\x06i\ai\bi\t", but it riskily, because data can be changed after ruby update (or I am wrong)
Can anybody to tell about true way?
Sequel supports Postgres Array columns natively, assuming you don’t need to normalize yourschema further.
How do I define an ARRAY column in a Sequel Postgresql migration?
http://sequel.jeremyevans.net/rdoc-plugins/files/lib/sequel/extensions/pg_array_rb.html
IMHO, The clean approach would be an extra table. Ideally, each row in the DB represent a single observation, and having an array or json column most probably contradicts that. I suggest looking at that extra table as good design, not as an overkill.
Make use of serialize provided by ActiveRecord
class User < ApplicationRecord
serialize :preferences, Array
end
#In migration Add a string field
class AddSerializePreferencesToUsers < ActiveRecord::Migration[5.1]
def change
add_column :users, :preferences, :string
end
end
#In rails console.
u = User.first
u.preferences # => []
u.preferences << 'keep coding'
u.preferences # => ['keep coding']
u.save
u.reload.preferences # ['keep coding']
Hope this helps

Query by multiple doc_ids in Google App Engine Search API

I want to retrieve a list of documents from a list of doc_ids. Something akin to doing the following in SQL:
SELECT * FROM Documents WHERE id IN (1,2,3,167,91)
I see this method in the documentation, but that only retrieves a single document. For efficiency, I want to do a batch retrieval. Is this possible?
I don't think there's a batch get function, but there is an async version (search https://cloud.google.com/appengine/docs/python/refdocs/google.appengine.api.search.search for get_async), so you could do something like (untested pseudo-code):
# query for docs ids in advance
futures = []
for id_ in doc_ids:
futures.append(index.get_async(id_))
# dereference the futures when you need them
ids = [x.get_result() for x in futures]

Query given keys

I would like to accomplish some sort of hybrid solution between ndb.get_multi() and Query().
I have a set of keys, that I can use with:
entities = ndb.get_multi(keys)
I would like to query, filter, and order these entities using Query() or some more efficient way than doing all myself in the Python code manually.
How do people go about doing this? I want something like this:
query = Entity.gql('WHERE __key__ in :1 AND prop1 = :2 ORDER BY prop2', keys, 'hello')
entities = query.fetch()
Edit:
The above code works just fine, but it seems like fetch() never uses values from cache, whereas ndb.get_multi() does. Am I correct about this? If not, is the gql+fetch method much worse than get_multi+manual processing?
There are no way to use a query on already fetched properties, unless you will write it by yourself, but all this stuff can be easily done with built-in python filters. Note that its more efficient to run a query if you have a big dataset, rather than get_multi hundreds of keys to get only 5 entities.
entities = ndb.get_multi(keys)
# filtering
entities = [e for e in entities if e.prop1 == 'bla' and e.prop2 > 3]
#sorting by multiple properties
entities = sorted(entities, key=lambda x: (x.prop1, x.prop2))
UPDATE: And yes, cache is only used when you receive your entity by key, it is not used when you query for entities.

How to write a query like SQL's SELECT x FROM

I want to write a query that does something like this SQL query:
SELECT name FROM contacts WHERE blah blah
I know I can do something like this:
for contact in Contacts.gql(WHERE_CLAUSE, args).fetch(1000):
print contact.name
but isn't there a way to get name directly from a query without having to loop on the results? would it provide any advantage in performance?
Nope. Can't be done.
A GQL query returns zero or more entities or Keys of the requested
kind. Every GQL query always begins with either SELECT * or SELECT
key. (A GQL query cannot perform a SQL-like "join" query.)
http://code.google.com/appengine/docs/python/datastore/gqlreference.html
But you can create a simple wrapper to do it for you. Something like:
def get_all_of_field(model, field):
for x in model.all():
yield getattr(x, field)
names = get_all_of_field(Contact, 'name')
Performance can't be improved that way as the entire "line" is read by the API no matter what. Either you read the entire "line" or just its key.
You can do this now using Projection queries. For db, see the documentation here:
https://developers.google.com/appengine/docs/python/datastore/projectionqueries
For ndb, see the documentation here:
https://developers.google.com/appengine/docs/python/ndb/queries#projection

Resources