Modelling data in ArangoDB vs MongoDB
This is a short tutorial showing you the comparison between performing queries in ArangoDB and MongoDB.
Both, ArangoDB and MongoDB, are “NoSQL databases” and might look pretty similar at first glance. When it comes to data modelling and data querying, they are somewhat different. The main difference being ArangoDB’s flexibility and functionality when working with graph data. In this 10 min tutorial we will show the differences in syntax between the two databases. We will have a look at some simple examples, but also touch base with a few more complex ones.
Let's get started
For this tutorial we are going to use two collections of data that are bundled in ArangoDB: worldVertices and worldEdges.
echo 'require("@arangodb/graph-examples/example-graph.js").loadGraph("worldCountry")' | arangosh --server.password ""
arangodump /tmp/arangoExport --server.password ""
Using arangodump
will export the raw data including some metadata which you could feed into another ArangoDB instance right away. However, to load the data into MongoDB we need to have the raw data without ArangoDB specific metadata. To extract the raw data we are using the jq
tool. The raw data is contained within the _data
key in the dump file.
jq
command available on your machine before the import.and import it into MongoDB:
cat /tmp/arangoExport/worldVertices_*.data.json | jq -c .data | mongoimport --collection worldVertices cat /tmp/arangoExport/worldEdges_*.data.json | jq -c .data | mongoimport --collection worldEdges
Now that you are all set, we can start with some query examples.
Find a document
The following query finds the first document matching a filter criteria. In the example below we are searching for the first document where the type is “country”. We don’t specify any sorting neither in MongoDB nor in ArangoDB, therefore the results are more or less random in both cases.
MongoDB
mongo > db.worldVertices.findOne( {type: 'country'} )
ArangoDB
mongo > db.worldVertices.findOne( {type: 'country'} )
The results will approximately look like this:
{ "_id" : "worldVertices/country-algeria", "_key" : "country-algeria", "_rev" : "233", "code" : "DZA", "name" : "Algeria", "type" : "country" }
{ "_key" : "country-brazil", "_id" : "worldVertices/country-brazil", "_rev" : "281", "code" : "BRA", "name" : "Brazil", "type" : "country" }
Find a list of documents
With the following query you will find all documents matching a set-up criteria. In this case all documents where type is “continent” will be displayed.
MongoDB
mongo > db.worldVertices.find( {'type': 'continent'} )
ArangoDB
arangosh > db.worldVertices.byExample( {'type': 'continent'} ).toArray()
The results should look like something like this:
{ "_id" : "worldVertices/continent-asia", "_key" : "continent-asia", "_rev" : "212", "name" : "Asia", "type" : "continent" } { "_id" : "worldVertices/continent-africa", "_key" : "continent-africa", "_rev" : "209", "name" : "Africa", "type" : "continent" } ...more
[ { "_key" : "continent-africa", "_id" : "worldVertices/continent-africa", "_rev" : "209", "name" : "Africa", "type" : "continent" }, { "_key" : "continent-australia", "_id" : "worldVertices/continent-australia", "_rev" : "215", "name" : "Australia", "type" : "continent" }, ...more ]
Update documents
Here we are going to update all documents that match a filter “type: country” with a “population: 10″.
MongoDB
mongo > db.worldVertices.update({type: 'country'}, { $set: {population: 10}}, { multi: true} )
ArangoDB
arangosh > db.worldVertices.updateByExample( {'type': 'country'}, {'population': 10} )
And the results that you will see:
WriteResult( { "nMatched" : 40, "nUpserted" : 0, "nModified" : 40 } )
40
Now that we have executed the query, let’s check if the update took place. For simplicity we are going to list one document that got updated.
Find a document
MongoDB
mongo > db.worldVertices.find( {'name': 'Australia', 'type': 'country'} )
ArangoDB
arangosh > db.worldVertices.firstExample( {'name': 'Australia', 'type': 'country'} )
The results that you will see will look like this:
{ "_id" : ObjectId("57aaf4a42cf4ab073b244ff7"), "theType" : 2300, "id" : "worldVertices/country-australia", "key" : "country-australia", "rev" : "Tk84gRS--", "code" : "AUS", "name" : "Australia", "type" : "country", "population" : "10" }
{ "_key" : "country-australia", "_id" : "worldVertices/country-australia", "_rev" : "2014", "code" : "AUS", "name" : "Australia", "type" : "country", "population" : 10 }
Note: Now that we have covered some simple steps, we are going to move on to a few more complex examples. Here we are going to use ArangoDB’s powerful & versatile SQL-like query language – AQL – for the first time.
Aggregate
Below is an example of how to use the aggregate function in both databases. Here we are going to group all documents in the worldVertices collection by their type and display what amount of population each type has.
MongoDB
mongo > db.worldVertices.aggregate( { $group: { _id: "$type", population: {$sum: "$population"} } } )
ArangoDB
arangosh > db._query(` FOR item IN worldVertices COLLECT types = item.type INTO group RETURN { _id: types, population: SUM(group[*].item.population) } `)
The results will look like something like this:
{ "_id" : "capital", "population" : 0 } { "_id" : "country", "population" : 400 } { "_id" : "continent", "population" : 0 } { "_id" : "root", "population" : 0 }
[ { "_id" : "capital", "population" : 0 } { "_id" : "country", "population" : 400 } { "_id" : "continent", "population" : 0 } { "_id" : "root", "population" : 0 } ]
Aggregate with a filter
The below example shows how to use the aggregate function with a filter. Here we will group all documents in the worldVertices collection by type, list the amount of population each type has, but by using the filter we will only see the result for type: “country”.
MongoDB
mongo > db.worldVertices.aggregate([ { $match: { type: "country"} }, { $group: { _id: "$type", population: {$sum: "$population"} } } ])
ArangoDB
arangosh > db._query(` FOR item IN worldVertices FILTER item.type == 'country' COLLECT types = item.type INTO group RETURN { _id: types, population: SUM(group[*].item.population) } `)
You will see the following results:
{ "_id" : "country", "population" : 400 }
[ { "_id" : "country", "population" : 400 } ]
Range select
With the range select function we are going to filter all documents in the worldVertices collection where the name range is between “Bul” and “Cb”.
MongoDB
mongo > db.worldVertices.find({ $and: [ { name: {$gt: 'Bul'}}, { name: {$lt: 'Cb'}} ] })
ArangoDB
arangosh > db._query(` FOR item IN worldVertices FILTER item.type == 'country' COLLECT types = item.type INTO group RETURN { _id: types, population: SUM(group[*].item.population) } `)
Your results will be like this:
{ "_id" : "worldVertices/country-bulgaria", "_key" : "country-bulgaria", "_rev" : "287", "code" : "BGR", "name" : "Bulgaria", "type" : "country", "population" : 10 } { "_id" : "worldVertices/country-burkina-faso", "_key" : "country-burkina-faso", "_rev" : "290", "code" : "BFA", "name" : "Burkina Faso", "type" : "country", "population" : 10 } { "_id" : "worldVertices/country-burundi", "_key" : "country-burundi", "_rev" : "293", "code" : "BDI", "name" : "Burundi", "type" : "country", "population" : 10 } .... more
[ { "_id" : "worldVertices/country-bulgaria", "_key" : "country-bulgaria", "_rev" : "287", "code" : "BGR", "name" : "Bulgaria", "type" : "country", "population" : 10 } { "_id" : "worldVertices/country-burkina-faso", "_key" : "country-burkina-faso", "_rev" : "290", "code" : "BFA", "name" : "Burkina Faso", "type" : "country", "population" : 10 } { "_id" : "worldVertices/country-burundi", "_key" : "country-burundi", "_rev" : "293", "code" : "BDI", "name" : "Burundi", "type" : "country", "population" : 10 } .... more ]
JOINs
With the following example we are going to do a JOIN between two documents in two collections (worldVertices and worldEdges). We will find out what the capital of Australia is.
MongoDB
mongo > db.worldVertices.aggregate( [ { $match: { name: 'Australia', type: 'country' }, }, { $lookup: { from: 'worldEdges', localField: '_id', foreignField: '_to', as: 'toCities' } }, { $unwind: "$toCities" }, { $lookup: { from: 'worldVertices', localField: 'toCities._from', foreignField: '_id', as: 'capital' } }, { $unwind: "$capital" }, { $match: { "capital.type":"capital" } }, { $project: { _id: 0, name: 1, "capital.name": 1 } } ] ).pretty()
ArangoDB
arangosh > db._query(` FOR country in worldVertices FILTER country.name == 'Australia' AND country.type == 'country' FOR edge in worldEdges FILTER edge._to == country._id FOR capital IN worldVertices FILTER capital._id == edge._from RETURN { name: country.name, capital: {name: capital.name} } `)
The results will look like this:
{ "name" : "Australia", "capital" : { "name" : "Canberra" } }
[ { "name" : "Australia", "capital" : { "name" : "Canberra" } } ]
Graph Queries:
What you can do with ArangoDB and cannot do with MongoDB
While querying the immediate connection in the graph (country to capital) is still doable via JOINs (previous examples above) it can rather quickly become more difficult once you dig deeper into the graph and perform more complex queries.
As the nature of our example data is a graph and ArangoDB is also a graph database, we can show you with the example below how this procedure can be done in an easier and neater way. In this case, ArangoDB offers more flexibility in comparison to MongoDB.
MongoDB
–
ArangoDB
arangosh > db._query(" FOR country in worldVertices FILTER country.name == 'Australia' AND country.type == 'country' FOR capital IN INBOUND country worldEdges RETURN { name: country.name, capital: {name: capital.name} } ")
Delete a set of documents
As the final step of this quick tutorial, we are going to delete a set of documents based on a filter – document type is “capital
MongoDB
First, count the documents in a collection:
mongo > db.worldVertices.count()
ArangoDB
arangosh > db.worldVertices.count()
The results should look like this:
87
.
87
Delete documents:
mongo > db.worldVertices.remove( {type: 'capital'} )
arangosh > db.worldVertices.removeByExample( {type: 'capital'} )
The results will be the following:
WriteResult( { "nRemoved" : 40 } )
40
Count the documents again to check:
mongo > db.worldVertices.count()
arangosh > db.worldVertices.count()
And the results should be:
47
47