Datomic - automatically retract missing component entities - datomic

I have a nested structure (that can also be deeply nested). All nested entities are marked as components. Creation works just fine.
{:db/id (d/tempid :db.part/user)
:tree/name "some tree"
:tree/nodes [{:node/name "Node1"
:node/prop "some prop"}
{:node/name "Node2"
:node/prop "another prop"}]}
Let's say the tree above is created. I pull it for an update and it looks like this:
{:db/id 1
:tree/name "some tree"
:tree/nodes [{:db/id 2
:node/name "Node1"
:node/prop "some prop"}
{:db/id 3
:node/name "Node2"
:node/prop "another prop"}]}
From the UI I remove the first node:
{:db/id 1
:tree/name "some tree"
:tree/nodes [{:db/id 3
:node/name "Node2"
:node/prop "another prop"}]}
How do I automatically remove the node with db/id 2? The only thing I can think of is pulling the nodes and comparing them to the nodes that I'm submitting. Because the structure can be nested more deeply I will need to traverse the collection recursively. Is there a more automatic way to do this?

The built-in transaction function retractEntity will recursively retract component entities:
http://docs.datomic.com/transactions.html#dbfn-retractentity

Related

Is there a way to auto generate ObjectIds inside arrays of MongoDB?

Below is my MongoDb collection structure:
{
"_id": {
"$oid": "61efa44933eabb748152a250"
},
"title": "my first blog",
"body": "Hello everyone,wazuzzzzzzzzzzzzzzzzzup",
"comments": [{
"comment": "fabulous work bruhv",
}]
}
}
Is there a way to auto generate ids for comments without using something like this:
db.messages.insert({messages:[{_id:ObjectId(), message:"Message 1."}]});
I found the above method from the SO question:
mongoDB : Creating An ObjectId For Each New Child Added To The Array Field
But someone in the comments pointed out that:
"I have been looking at how to generate a JSON insert using ObjectID() and in my travels have found that this solution is not very good for indexing. The proposed solution has _id values that are strings rather than real object IDs - i.e. "56a970405ba22d16a8d9c30e" is different from ObjectId("56a970405ba22d16a8d9c30e") and indexing will be slower using the string. The ObjectId is actually represented internally as 16 bytes."
So is there a better way to do this?

iterate over PersistentVector of objects in clojure

I am new to Clojure and I am trying to iterate over a PersistentVector of objects, which looks like below when I print in logs.
[{name John, email john#example.com} {name Peter, email peter#example.com}]
when I print (type myData) it tells me it is of type clojure.lang.PersistentVector
I have to iterate over this vector, extract email from each object inside it at a time and invoke another function.
It looks very simple, I looked at many samples and questions, but nothing seem to work for me :(
Thanks.
Here are a couple of options:
If you don't care about the objects ("maps" in Clojure speak) and only want to collect the emails and apply a function over them, you can create a simple function just to extract the emails into another collection and then use any function over the collection of emails:
(def items
[{"name" "John", "email" "john#example.com"} {"name" "Peter", "email" "peter#example.com"}])
(defn get-email [m]
(get m "email"))
(mapv get-email items)
;; returns: ["john#example.com", "peter#example.com"]
You can use function composition to the create a function that turns into upper case (using upper-case from clojure.string) the result of getting the email: (note the ordering in comp):
(mapv (comp clojure.string/upper-case get-email) items)
;; returns ["JOHN#EXAMPLE.COM" "PETER#EXAMPLE.COM"]
If you want to obtain a similar collection but with the email field updated, you can use update-in:
(mapv (fn [m] (update-in m ["email"] clojure.string/upper-case)) items)
;; Applies `upper-case` to the "email" path of each map identified by `m`.
;; returns: [{"name" "John", "email" "JOHN#EXAMPLE.COM"} {"name" "Peter", "email" "PETER#EXAMPLE.COM"}]
There are more elegant ways to do the same work using other techniques (anonymous functions, strs destructuring) but I think the ones above are simpler to understand if you are new to Clojure.

Spring-Data/MongoDB/QueryDSL Searching nested _id of ObjectId type

When an document from a collection is nested inside a document of another collection, it's pretty standard to make a copy of the nested document verbatim instead of creating another type of document just for the sake of nesting. Ex:
category {"_id": ObjectId("c1"), "name": "Category 1"}
question {"_id": ObjectId("q1"), category: {"_id": ObjectId("c1"), "name": "Category 1"}}
When using queryDSL as follows:
question.category.id = "c1"
queryDSL generates a query like this:
"question.category._id":"c1"
where I expect:
"question.category._id":ObjectId("c1")
This works for top level documents, not for nested. I think this is a valid case and Spring should do the same translations it does for top level search. Is there a workaround for that?

Batch node relationship creation in cypher/neo4j

What is the most efficient way to break down this CREATE cypher query?
The end pattern is the following:
(newTerm:term)-[:HAS_META]->(metaNode:termMeta)
In this pattern this is a single newTerm node and about ~25 termMeta nodes. The HAS_META relationship will have a single property (languageCode) that will be different for each termMeta node.
In the application, all of these nodes and relationships will be created at the same time. I'm trying to determine the best way to add them.
Is there anyway to add these without having to have perform individual query for each TermMeta node?
I know you can add multiple instances of a node using the following query format:
"metaProps" : [
{"languageCode" : "en", "name" : "1", "dateAdded": "someDate1"},
{"languageCode" : "de", "name" : "2", "dateAdded": "someDate2"},
{"languageCode" : "es", "name" : "3", "dateAdded": "someDate3"},
{"languageCode" : "fr", "name" : "3", "dateAdded": "someDate4"}
]
But you can only do that for one type of node at a time and there (as far as I can tell) is no way to dynamically add the relationship properties that are needed.
Any insight would be appreciated.
There's no really elegant way to do it, as far as I can tell—from your example, I'm assuming you're using parameters. You can use a foreach to loop through the params and do a create on each one, but it's pretty ugly, and requires you to explicitly specify literal maps of your properties. Here's what it would look like for your example:
CREATE (newTerm:term)
FOREACH ( props IN {metaProps} |
CREATE newTerm-[:HAS_META {languageCode: props.languageCode}]->
(:termMeta {name: props.name, dateAdded: props.dateAdded})
)
WITH newTerm
MATCH newTerm-[rel:HAS_META]->(metaNode:termMeta)
RETURN newTerm, rel, metaNode
If you don't need to return the results, you can delete everything after the FOREACH.
Select and name each vertex differently and then create relations using it.
For ex
match (n:Tag), (m:Account), (l:FOO) CREATE (n)-[r:mn]->(m),(m)-[x:ml]->(l)
match (n:Tag{a:"a"}), (m:Account{b:"x"}), (l:FOO) CREATE (n)-[r:mn]->(m),(m)-[x:ml]->(l)

Renaming a field in an embedded Document in an Array in MongoDB not working

Step One
> db.myCollection.find();
{ "_id" : ObjectId("2358523892345"), "field1" : "value 1", "field2" : [ { "subfield1" : "value 2" }, { "Subfield2" : "value 3" } ], "field3" : "value 4" }
I am wanting to rename the field Subfield2 to subfield2. I tried:
Step Two
> db.myCollection.update ( { "field3": "value 4" }, {$rename: {"Subfield2": "subfield2" } } )
And then ran find() again and get the same results as in 'Step One' ie the field is not renamed.
Using MongoDB terminology, I think what I am trying to do is 'rename a field in an embedded document in an array'.
References
http://docs.mongodb.org/manual/reference/operator/rename/
It seems to not be possible to rename a field within an array from the command line as answered in this question:
MongoDB rename database field within array
As mentioned in the documentation there is no way to rename fields
within arrays. Your only option is to iterate over your collection
documents, read them and update each with $unset old/$set new
operations.
It is possible to change these values via RockMongo however as suggested by user Liad Livnat.
For my particular instance, whist there I also removed the array and changed the structure to:
{
"field1": "value 1",
"field2": {"subfield1": "value 2", "subfield2": "value 3"},
"field3": "value 4"
}
Querying this object was then possible with:
db.myCollection.find( {"field2.subfield2":"value 3"} );
if you want to update it manually i suggest you will install rockmongo, rockmongo is a great tool working with mongo databases, just extract it on your server and connect to your database.
there you will find very easy update to mongo database, tables and records.
rock mongo

Resources