ArangoDB Retrieve parent object based on multiple filters on children properties - arangodb

I have a Person object as follows
{
name: 'John Doe'
properties:
[
{
name: 'eyeColor',
value: 'brown'
},
{
name: 'age',
value: 25
},
{
name: 'interest',
value: 'reading'
},
{
name: 'interest',
value: 'diving'
}
]
}
Now I want to be able to filter my object based on multiple properties. In pseudocode:
Return all people for which
there exists any p.property such that
p.property.propertyname == 'interest'
AND p.property.propertyvalue == 'reading'
AND there exists any p.property such that
p.property.propertyname == 'age'
AND p.property.propertyvalue < 30
What is the most concise and extensible (I want to be able to apply N of these filters) of doing this without having too many intermediate results?

Related

How to Perform UPSERT Operation in Arango DB with Different multiple keys (Composite Key)?

In official documentations, it's already shown how to do that. Below, an example that working fine:
Example: 1
LET documents = [
{ name: 'Doc 1', value: 111, description: 'description 111' },
{ name: 'Doc 2', value: 222, description: 'description 2' },
{ name: 'Doc 3', value: 333, description: 'description 3' }
]
FOR doc IN documents
UPSERT { name: doc.name, description: doc.description }
INSERT doc
UPDATE doc
IN MyCollection
But, I want to check different multiple keys for each document on UPSERT, like:
Example: 2
LET documents = [
{ name: 'Doc 1', value: 777, description: 'description 111' },
{ name: 'Doc 2', value: 888, description: 'description 2' },
{ name: 'Doc 3', value: 999, description: 'description 3' }
]
FOR doc IN documents
UPSERT {
{ name: doc.name, description: doc.description },
{ value: doc.value, description: doc.description },
{ name: doc.name, value: doc.value }
}
INSERT doc
UPDATE doc
IN MyCollection
Or, any other other way (using filter or something). I had tried but nothing works
If I understand your problem, you would want to update a document, if there's an existing one with at least 2 fields matching, otherwise insert it as new.
UPSERT won't be able to do that. It can only do one match. So a subquery is necessary. In the solution below, I ran a query to find the key of the first document that matches at least 2 fields. If there's no such document then it will return null.
Then the UPSERT can work by matching the _key to that.
LET documents = [
{ name: 'Doc 1', value: 777, description: 'description 111' },
{ name: 'Doc 2', value: 888, description: 'description 2' },
{ name: 'Doc 3', value: 999, description: 'description 3' }
]
FOR doc IN documents
LET matchKey= FIRST(
FOR rec IN MyCollection
FILTER (rec.name==doc.name) + (rec.value==doc.value) + (rec.description==doc.description) > 1
LIMIT 1
RETURN rec._key
)
UPSERT {_key:matchKey}
INSERT doc
UPDATE doc
IN MyCollection
Note: There's a trick with adding booleans together which works because true will be converted to 1, while false is zero. You can write it out explicitly like this: (rec.name==doc.name?1:0)
While this will work for you it's not a very effective solution. Actually there's no effective one in this case because all the existing documents need to be scoured through to find a matching one, for each document to be added/updated. I'm not sure what kind of problem you are trying to solve with this, but it might be better to re-think your design so that the matching condition could be more simple.

Find all objects that contain a property with a given key using JPath

Is it possible to (and if so how do I) recursively get a list of all objects within an object that contains a property with a given key or a given key in a set of keys using JPath?
Example
For this object searching for the type property:
[
{
type: 'text'
},
{
type: 'folder',
children:
[
{
type: 'text'
}
]
},
{
name: 'Some object without a type'
}
]
I would get:
[
{
type: 'text'
},
{
type: 'folder'
children:
[
{
type: 'text'
}
]
},
{
type: 'text'
}
]
I found the answer. You can use this query syntax:
$..[?(#.type)]
To explain it:
$ is the root node selector
.. is the recursive query syntax
[...] Subscript operator
?(...) is the expression/ filter syntax
#.type checks for the existence of the type property on the current node being evaluated
as outlined on
https://goessner.net/articles/JsonPath/

What is the best way to store constant strings in MongoDB?

In my nodejs app I have collection - football_players. Docs in this collection have information about role of the player. For example:
[
{
id: 'some_id_1',
name: 'Player1',
role: 'FORWARD',
},
{
id: 'some_id_2',
name: 'Player2',
role: 'DEFENDER',
},
{
id: 'some_id_3',
name: 'Player3',
role: 'FORWARD',
},
]
All types of role are constants. What is the best way to store it in MongoDB:
as strings (like in my example)
make declaration:
const roles = { FORWARD: 1, DEFENDER: 2 };
store as numbers and use this declaration in my nodejs app? Like: player.role === roles.FORWARD ? 'Great!' : 'He cann\'t score a goal'; ?
Is there any performance reason to use second way? Are there any other reasons to use first way?

Simpler way to get duplicates from a list in groovy

Given the list:
list: [
object1: {
id: 22,
name: "Tom"
},
object2: {
id: 12,
name: "Mary"
},
object3: {
id: 44,
name: "Tom"
}
]
Instead of using nested loops, is there any other one-liner that would get ONLY duplicated names from this list ? So the return list would be ["Tom"]
Another way would be to group them with a count, and find all the ones where the count is greater than one:
list.name.countBy { it }.findResults { it.value > 1 ? it.key : null }
Or indeed as #Daniel says:
list.values().name.countBy { it }.findResults { it.value > 1 ? it.key : null }
Depending on your structure...
Close to a oneliner is the below code. The idea is to create a list of unique named elements, and remove them from the original list.
def list = [
[ id: 22, name: "Tom"],
[ id: 12, name: "Mary"],
[ id: 44, name: "Tom"]
]
def unique = list.toUnique { a, b -> a.name <=> b.name }
list.removeAll(unique)
list*.name
removeAll returns booleon, so that complicates it if you need 1 line of code, the unique variable can be foldet into the method call.
Notice, .toUnique() returns a new collection .unique() removes from the collection called on.

Using json builder

I want something like this in my application with json builder
new JsonBuilder() {
persons.collect{
[
name: it.name,
age: it.age,
companies: [{
company1: it.company //The company comes from person object.
},
{
company2: it.company
}
]
]
}
}
Here while accessing the company null pointer exception is being thrown as it is not considering the person iterator.Is there any other way to do it in this way??
you can define the name of iterator (closure default parameter name - it)
new JsonBuilder() {
persons.collect{person->
[
name: person.name,
age: person.age,
companies: [
{
company1: person.company //The company comes from person object.
},
{
company2: person.company
}
]
]
}
}

Resources