diff --git a/src/server/SparqlSearchEngine.js b/src/server/SparqlSearchEngine.js
deleted file mode 100644
index a6e6f33cd430c2958d837f7cbd3a04f4bf168e18..0000000000000000000000000000000000000000
--- a/src/server/SparqlSearchEngine.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import SparqlApi from './SparqlApi';
-import datasetConfig from './Datasets';
-import {
-  mapAllResults,
-  mergeAllResults
-} from './Mappers';
-import { makeObjectList } from './SparqlObjectMapper';
-
-class SparqlSearchEngine {
-
-  doSearch(sparqlQuery, sparqlApi, mapper) {
-    return sparqlApi.selectQuery(sparqlQuery)
-      .then((data) => {
-        if (data.results.bindings.length === 0) {
-          return [];
-        }
-        // console.log(data.results.bindings)
-        return mapper ? mapper(data.results.bindings) : data.results.bindings;
-      });
-  }
-
-  getAllManuscripts(datasetId) {
-    const { endpoint, getAllQuery } = datasetConfig[datasetId];
-    const sparqlApi = new SparqlApi({ endpoint });
-    //console.log(getAllQuery)
-    return this.doSearch(getAllQuery, sparqlApi, makeObjectList);
-  }
-
-  getFederatedManuscripts(datasets) {
-    return Promise.all(datasets.map((datasetId) =>
-      this.getAllManuscripts(datasetId))).then(mergeAllResults);
-  }
-}
-
-export default new SparqlSearchEngine();
diff --git a/src/server/index.js b/src/server/index.js
index 9459bd2204ae2abecc6a7ed440f44652b5c7a2c7..e14fa2fc8fd2309205f0d1197fc0a65096435787 100644
--- a/src/server/index.js
+++ b/src/server/index.js
@@ -2,7 +2,7 @@ import express from 'express';
 import bodyParser from 'body-parser';
 import request from 'superagent';
 import _ from 'lodash';
-import sparqlSearchEngine from './SparqlSearchEngine';
+import sparqlSearchEngine from './sparql/SparqlSearchEngine';
 const DEFAULT_PORT = 3001;
 const app = express();
 //const isDevelopment  = app.get('env') !== 'production';
diff --git a/src/server/Datasets.js b/src/server/sparql/Datasets.js
similarity index 78%
rename from src/server/Datasets.js
rename to src/server/sparql/Datasets.js
index 29c1125e5c7ca33515d788f85d6210cbd657615a..ba46cbae5976c3ea4437f0cb89fc4783533ada75 100644
--- a/src/server/Datasets.js
+++ b/src/server/sparql/Datasets.js
@@ -6,7 +6,7 @@ module.exports = {
     'timePeriod': '',
     //'endpoint': 'http://ldf.fi/mmm-sdbm-cidoc/sparql',
     'endpoint': 'http://localhost:3034/ds/sparql',
-    'getAllQuery': `
+    'allQuery': `
       PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
       PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
       PREFIX foaf: <http://xmlns.com/foaf/0.1/>
@@ -20,12 +20,12 @@ module.exports = {
       PREFIX sdbm: <https://sdbm.library.upenn.edu/>
       SELECT
       ?id ?sdbm_id
-      (GROUP_CONCAT(DISTINCT ?label_id; SEPARATOR=", ") AS ?label)
-      (GROUP_CONCAT(DISTINCT ?author_id; SEPARATOR=", ") AS ?author)
-      (GROUP_CONCAT(DISTINCT ?timespan_id; SEPARATOR=", ") AS ?timespan)
-      (GROUP_CONCAT(DISTINCT ?creation_place_id; SEPARATOR=", ") AS ?creationPlace)
-      (GROUP_CONCAT(DISTINCT ?material_id; SEPARATOR=", ") AS ?material)
-      (GROUP_CONCAT(DISTINCT ?language_id; SEPARATOR=", ") AS ?language)
+      (GROUP_CONCAT(DISTINCT ?label_id; SEPARATOR=",") AS ?label)
+      (GROUP_CONCAT(DISTINCT ?author_id; SEPARATOR=",") AS ?author)
+      (GROUP_CONCAT(DISTINCT ?timespan_id; SEPARATOR=",") AS ?timespan)
+      (GROUP_CONCAT(DISTINCT ?creation_place_id; SEPARATOR=",") AS ?creationPlace)
+      (GROUP_CONCAT(DISTINCT ?material_id; SEPARATOR=",") AS ?material)
+      (GROUP_CONCAT(DISTINCT ?language_id; SEPARATOR=",") AS ?language)
       WHERE {
         ?id a frbroo:F4_Manifestation_Singleton .
         ?id rdfs:label ?label_id .
@@ -42,6 +42,21 @@ module.exports = {
       }
       GROUP BY ?id ?sdbm_id
       `,
+    'placeQuery': `
+      PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+      PREFIX wgs84: <http://www.w3.org/2003/01/geo/wgs84_pos#>
+      PREFIX dc: <http://purl.org/dc/elements/1.1/>
+      SELECT DISTINCT ?id ?label ?lat ?long ?source
+      WHERE {
+        VALUES ?id { <ID> }
+        ?id skos:prefLabel ?label .
+        OPTIONAL {
+          ?id wgs84:lat ?lat ;
+              wgs84:long ?long .
+        }
+        OPTIONAL { ?id dc:source ?source . }
+      }
+        `,
     'tgn': {
       // Getty LOD documentation:
       // http://vocab.getty.edu/queries#Places_by_Type
diff --git a/src/server/Mappers.js b/src/server/sparql/Mappers.js
similarity index 100%
rename from src/server/Mappers.js
rename to src/server/sparql/Mappers.js
diff --git a/src/server/SparqlApi.js b/src/server/sparql/SparqlApi.js
similarity index 100%
rename from src/server/SparqlApi.js
rename to src/server/sparql/SparqlApi.js
diff --git a/src/server/SparqlObjectMapper.js b/src/server/sparql/SparqlObjectMapper.js
similarity index 88%
rename from src/server/SparqlObjectMapper.js
rename to src/server/sparql/SparqlObjectMapper.js
index c31f2f8ab44f80fd25013da09b9b3ac6298b021d..09f02ebdd361932d3e3128cf43473af0454c6f19 100644
--- a/src/server/SparqlObjectMapper.js
+++ b/src/server/sparql/SparqlObjectMapper.js
@@ -23,6 +23,10 @@ export const makeObjectList = (objects) => {
   //return self.postProcess(objList);
 };
 
+export const makeDict = (objects) => {
+  return arrayToObject(objects, 'id');
+};
+
 /**
 * @param {Object} obj A single SPARQL result row object.
 * @returns {Object} The mapped object.
@@ -114,3 +118,15 @@ const merger = (a, b) => {
   }
   return mergeObjects(a, b);
 };
+
+const arrayToObject = (array, keyField) =>
+  array.reduce((obj, item) => {
+    let newItem = {};
+    Object.entries(item).forEach(([key, value]) => {
+      if (key !== keyField) {
+        newItem[key] = value.value;
+      }
+    });
+    obj[item[keyField].value] = newItem;
+    return obj;
+  }, {});
diff --git a/src/server/sparql/SparqlSearchEngine.js b/src/server/sparql/SparqlSearchEngine.js
new file mode 100644
index 0000000000000000000000000000000000000000..6d94d9c341cb6555bb64acdbe282037e572968a4
--- /dev/null
+++ b/src/server/sparql/SparqlSearchEngine.js
@@ -0,0 +1,77 @@
+import _ from 'lodash';
+import SparqlApi from './SparqlApi';
+import datasetConfig from './Datasets';
+import {
+  //mapAllResults,
+  mergeAllResults
+} from './Mappers';
+import { makeObjectList, makeDict } from './SparqlObjectMapper';
+
+class SparqlSearchEngine {
+
+  doSearch(sparqlQuery, endpoint, mapper) {
+    const sparqlApi = new SparqlApi({ endpoint });
+    return sparqlApi.selectQuery(sparqlQuery)
+      .then((data) => {
+        if (data.results.bindings.length === 0) {
+          return [];
+        }
+        // console.log(data.results.bindings)
+        return mapper ? mapper(data.results.bindings) : data.results.bindings;
+      });
+  }
+
+  getAllManuscripts(datasetId) {
+    const { endpoint, allQuery } = datasetConfig[datasetId];
+    return this.doSearch(allQuery, endpoint, makeObjectList);
+  }
+
+  getFederatedManuscripts(datasets) {
+    return Promise.all(datasets.map((datasetId) =>
+      this.getAllManuscripts(datasetId)))
+      .then(mergeAllResults)
+      .then((manuscripts) => this.getPlaces(manuscripts));
+  }
+
+  getPlaces(manuscripts) {
+    const { endpoint, placeQuery } = datasetConfig.mmm;
+    let placeIds = manuscripts.reduce((places, manuscript) => {
+      if (manuscript.creationPlace !== undefined) {
+        const creationPlaceArr = manuscript.creationPlace.split(',');
+        places = places.concat(creationPlaceArr);
+      }
+      return places;
+    }, []);
+    placeIds = Array.from(new Set(placeIds)); //remove duplicates
+    return this.doSearch(placeQuery.replace('<ID>', this.uriFy(placeIds)), endpoint, makeDict)
+      .then((placeDict) => {
+        manuscripts.map((manuscript) => {
+          if (manuscript.creationPlace !== undefined) {
+            let creationPlaceObjs;
+            const creationPlaceArr = manuscript.creationPlace.split(',');
+            if (creationPlaceArr.length > 1) {
+              creationPlaceObjs = creationPlaceArr.map((place) => {
+                return placeDict[place];
+              });
+            } else {
+              creationPlaceObjs = placeDict[creationPlaceArr[0]];
+            }
+            manuscript.creationPlace = creationPlaceObjs;
+            return manuscript;
+          }
+        });
+        return manuscripts;
+      });
+  }
+
+  uriFy(id) {
+    if (_.isArray(id)) {
+      return '<' + id.join('> <') + '>';
+    } else if (id) {
+      return '<' + id + '>';
+    }
+    return;
+  }
+}
+
+export default new SparqlSearchEngine();