Nest - Need help on elastic response mocking - elasticsearch

"aggregations" : {
"filter#count_stats" : {
"doc_count" : 30,
"lterms#Name1" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : 53986,
"doc_count" : 2,
"sterms#Name2" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "Soft",
"doc_count" : 7,
},
{
"key" : "Health",
"doc_count" : 5
},
]
}
},
{
"key" : 40127,
"doc_count" : 1,
"sterms#Name3" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "XYZ",
"doc_count" : 3
}
]
}
}
]
}
}
}

IReadOnlyDictionary<string, IAggregate> dictionary = new Dictionary<string, IAggregate>();
var keyedAggregate1 = new KeyedBucket<object>(dictionary) { Key = "Soft", DocCount = 7};
var keyedAggregate2 = new KeyedBucket<object>(dictionary) { Key = "Health", DocCount = 8 };
var keyedAggregate3 = new KeyedBucket<object>(dictionary) { Key = "XYZ", DocCount = 3 };
var backingListDeals1 = new List<IBucket>
{
keyedAggregate1,
keyedAggregate2
};
var backingListDeals2 = new List<IBucket>
{
keyedAggregate3
};
var bucketAggregate1 = new BucketAggregate()
{
Items = backingListDeals1,
DocCount = 2
};
var bucketAggregate2 = new BucketAggregate()
{
Items = backingListDeals2,
DocCount = 2
};
var backingDictionary = new Dictionary<string, IAggregate> {{"count_stats", new BucketAggregate
{
Items = new List<IBucket>
{
new KeyedBucket<object>(new Dictionary<string, IAggregate>{{ "Name2", bucketAggregate1 } })
{
Key = "53986",
DocCount = 2
},
new KeyedBucket<object>(new Dictionary<string, IAggregate>{{ "Name2", bucketAggregate2 } })
{
Key = "40127",
DocCount = 1
}
}
}}};
var singleBucketAggregate = new SingleBucketAggregate(backingDictionary);
IReadOnlyDictionary<string, IAggregate> backingDictionary = new Dictionary<string, IAggregate>
{
{ "count_stats", singleBucketAggregate }
};
return new AggregateDictionary(backingDictionary);

Related

Search in MongoDB with the condition to get only one result per attribute with the higehst version

Excuse my newbie question but I can't figure it out.
This is my collection:
[
{
_id: "A",
uuid: "12345",
version: 1,
test: "data1"
},
{
_id: "B",
uuid: "56566",
version: 1,
test: "data2"
},
{
_id: "C",
uuid: "12345",
version: 2,
test: "data3"
}
]
I'm looking for a query with a UuidContains condition and with a exact condition.
findByUuidContains(5)
-> Result: [B,C] as Object Array
findByUuidContains(12345)
-> Result: [C] as Object Array
findByUuidContains(66)
-> Result: [B]
Is this kind of query possible?
In words:
Select all Object that uuid contains ${value} and from the resultset select only one per uuid with the highest Version.
EDIT1:
I changed the group projection from answer:
db.collection.aggregate([
{
"$redact": {
"$cond": [
{
"$gt": [
{
"$indexOfCP": [
{
"$toLower": "$uuid"
},
"5"
]
},
-1
]
},
"$$KEEP",
"$$PRUNE"
]
}
},
{
$sort: {
version: -1
}
},
{
$group: {
_id: {
uuid: "$uuid"
},
version: {
$first: "$version"
},
id: {
$first: "$_id"
},
test: {
$first: "$test"
}
}
},
{
"$project": {
num: "1",
id: 1,
_id: 0,
version: 1,
test: 1
}
},
{
"$group": {
"_id": "$num",
"result": {
"$addToSet": {
id: "$id",
version: "$version",
test: "$test"
}
}
}
},
{
"$project": {
_id: 0,
result: 1
}
}
])
and I added some test data attributes to my documents. Now I have to 'translate' it into the spring boot 'language'
EDIT2:
I'm currently trying to translate the second answer but I can't figure out how the GroupOpertaion in Spring works. Somebody familiar with it? The first and second operation works like the mongo query operations but it failed by the group operation
String uuidRegexExp = String.format(".*%s.*", uuidSegment);
Pattern uuidPattern = Pattern.compile(uuidRegexExp);
MatchOperation match = new MatchOperation(Criteria.where("uuid").regex(uuidPattern));
SortOperation sort = Aggregation.sort(Sort.Direction.DESC,"version");
GroupOperation grup = Aggregation.group("version").first("version").as("version");
Aggregation aggregate = Aggregation.newAggregation(
match, sort, grup
);
AggregationResults<Example> aggregate1 = mongoTemplate.aggregate(aggregate, Example.COLLECTION_NAME, Example.class);
aggregate1.getMappedResults().forEach(er -> log.info(er.toString()));
This is the example class:
#Data
#Document(Example.COLLECTION_NAME)
public class Example {
public static final String COLLECTION_NAME = "Example";
public static final String FIELD_UUID_NAME = "uuid";
public static final String FIELD_HOST_NAME = "host";
public static final String FIELD_URL_NAME = "url";
public static final String FIELD_VERSION_NAME = "version";
public static final String FIELD_ID_NAME = "_id";
#Field(FIELD_ID_NAME)
private ObjectId _id;
#Field(FIELD_UUID_NAME)
private String uuid;
#Field(FIELD_HOST_NAME)
private String host;
#Field(FIELD_URL_NAME)
private String url;
#Field(FIELD_VERSION_NAME)
private Long version;
}
EDIT3:
I think I have done it. Here is the Code in a not pretty version:
String uuidRegexExp = String.format(".*%s.*", uuidSegment);
Pattern uuidPattern = Pattern.compile(uuidRegexExp);
MatchOperation match = new MatchOperation(Criteria.where("uuid").regex(uuidPattern));
SortOperation sort = Aggregation.sort(Sort.Direction.DESC,"version");
GroupOperation grup = Aggregation.group("uuid").first("version").as("version").first("_id").as("id");
ProjectionOperation project = Aggregation.project().and("_id").as("uuid").and("version").as("version").and("id").as("_id");
Aggregation aggregate = Aggregation.newAggregation(
match, sort, grup,project
);
AggregationResults<Example> aggregate1 = mongoTemplate.aggregate(aggregate, SingleRawArticle.COLLECTION_NAME, Example.class);
Is this something you are looking for? I have created mongo playground for it. You can check the query by passing diffrent parameters. I have used 5 in example like below. But i have also tried with 12345 and 66 and it looks fine to me.
{
"$indexOfCP": [
{
"$toLower": "$uuid"
},
"5"
]
},
Mongo Playground
Here is the query :
db.collection.aggregate([
{
"$redact": {
"$cond": [
{
"$gt": [
{
"$indexOfCP": [
{
"$toLower": "$uuid"
},
"5"
]
},
-1
]
},
"$$KEEP",
"$$PRUNE"
]
}
},
{
$sort: {
version: -1
}
},
{
$group: {
_id: {
uuid: "$uuid"
},
version: {
$first: "$version"
},
id: {
$first: "$_id"
}
}
},
{
"$project": {
num: "1",
id: 1,
_id: 0
}
},
{
"$group": {
"_id": "$num",
"result": {
"$addToSet": "$id"
}
}
},
{
"$project": {
_id: 0,
result: 1
}
}
])
check the below query to get the documents matching the given string. I have used regex to match the input string.
db.collection.aggregate(
[
{
"$match" : {
"uuid" : {
"$regex" : ".*5.*"
}
}
},
{
"$sort" : {
"version" : -1.0
}
},
{
"$group" : {
"_id" : {
"uuid" : "$uuid"
},
"uuid" : {
"$first" : "$uuid"
},
"id" : {
"$first" : "$_id"
},
"version" : {
"$first" : "$version"
}
}
},
{
"$project" : {
"_id" : "$id",
"uuid" : 1.0,
"version" : 1.0
}
}
],
{
"allowDiskUse" : false
}
);
Output:
{
"uuid" : "12345",
"version" : 2.0,
"_id" : "C"
}
{
"uuid" : "56566",
"version" : 1.0,
"_id" : "B"
}
Java code equivalent to query. Modified your edit according to the latest changes. Changed variable names to be more specific.
String uuidRegexExp = String.format(".*%s.*", uuidSegment);
MatchOperation match = new MatchOperation(Criteria.where("uuid").regex(Pattern.compile(uuidRegexExp)));
SortOperation sort = Aggregation.sort(Sort.Direction.DESC,"version");
GroupOperation group = Aggregation.group("uuid").first("version").as("version").first("_id").as("id").first("uuid").as("uuid");
ProjectionOperation project = Aggregation.project().and("uuid").as("uuid").and("version").as("version").and("id").as("_id");
Aggregation aggregation = Aggregation.newAggregation(
match, sort, group,project
);
AggregationResults<Example> aggregate = mongoTemplate.aggregate(aggregation, SingleRawArticle.COLLECTION_NAME, Example.class);

Spring Data MongoDB building dynamic query

Need help to build dynamic MongoDB query.
everything inside the "$or" Array is dynamic.
db.group.find({
"version" : NumberLong(0),
"$or" : [{
"$and" : [
{
"object_type" : "D"
},
{
"type" : "R"
},
{
"name" : "1"
}
]
},{
"$and" : [
{
"object_type" : "D"
},
{
"type" : "E"
},
{
"name" : "2"
}
]
]
});
Did the below spring data query but doesn't work
Criteria criteria = Criteria.where("version").is("123");
List<Criteria> docCriterias = new ArrayList<Criteria>();
groups.stream().forEach(grp -> {
docCriterias.add(Criteria.where("type").is(grp.get("type").toString())
.andOperator(Criteria.where("object_type").is(grp.get("objectType").toString()))
.andOperator(Criteria.where("name").is(grp.get("name").toString())));
});
criteria.orOperator((Criteria[]) docCriterias.toArray());
Query q = new Query(criteria);
Thanks for the help
You should pay attention to how you combine the operators.
The ff code should work for you (note this is groovy remember to change the closure into to java lambda expression):
List<Criteria> docCriterias = new ArrayList<Criteria>();
List groups = [
[
type: "type1",
object_type: "object_type1",
name: "name1"
],
[
type: "type2",
object_type: "object_type2",
name: "name2"
],
[
type: "type3",
object_type: "object_type3",
name: "name3"
],
]
groups.stream().each {grp ->
docCriterias.add(new Criteria().andOperator(
Criteria.where("type").is(grp.get("type")),
Criteria.where("object_type").is(grp.get("object_type")),
Criteria.where("name").is(grp.get("name"))
))
};
Criteria criteria = new Criteria().andOperator(
Criteria.where("version").is("123"),
new Criteria().orOperator(docCriterias.toArray(new Criteria[docCriterias.size()]))
);
Query q = new Query(criteria);
Which will give you this query:
{
"$and":[
{
"version":"123"
},
{
"$or":[
{
"$and":[
{
"type":"type1"
},
{
"object_type":"object_type1"
},
{
"name":"name1"
}
]
},
{
"$and":[
{
"type":"type2"
},
{
"object_type":"object_type2"
},
{
"name":"name2"
}
]
},
{
"$and":[
{
"type":"type3"
},
{
"object_type":"object_type3"
},
{
"name":"name3"
}
]
}
]
}
]
},
Fields:{
},
Sort:{
}
You could reach this using MongoDB Aggregation Pipeline in Json and Apache Velocity to customize more the Query, then execute this using db.runCommand using Spring MongoTemplate.
Example:
monodb_client_dynamic_query.vm
{
"aggregate": "client",
"pipeline": [
{
"$match" : {
"$and" : [
{
"is_removed" : {
"$ne" : [
true
]
}
},
{
"errors" : {
"$size" : 0.0
}
},
{
"client_id": "$velocityMap.client_id"
}
]
}
},
{
"$project" : {
"_id" : -1.0,
"account" : "$_id.account",
"person_id" : "$_id.person_id",
"begin_date": { $dateToString: { format: "%Y-%m-%d", date: "$value.begin_date" } },
"end_date": { $dateToString: { format: "%Y-%m-%d", date: "$value.end_date" } }
}
}
]
}
Then execute using MondoTemplate:
String script = ...load from file the script monodb_client_dynamic_query.vm
Map parameters = ... put all variables to replace in the mongodb script
String scriptNoSql = VelocityUtil.loadTemplateVM(script, parameters);
DBObject dbObject = (BasicDBObject) JSON.parse(scriptNoSql);
if (null == dbObject) {
return;
}
DB db = mongoTemplate.getDb();
CommandResult result = db.command(dbObject);
if(!result.ok()) {
throw result.getException();
}

scroll_id returns 0 hits when used the second time

I have this code to get the scroll_id after doing the first search:
var initSearch = client.LowLevel.Search<dynamic>(INDEX, TYPE, QUERY, x => x.AddQueryString("scroll", "1m").AddQueryString("size", "2"));
string scrollId = initSearch.Body["_scroll_id"].ToString();
then I used the scrollid during the 2nd search but it didn't return any hits
var scrollSearch = client.LowLevel.ScrollGet<dynamic>(x =>
x.AddQueryString("scroll", "1m").AddQueryString("scroll_id", scrollId));
scrollId = scrollSearch.Body["_scroll_id"].ToString();
var searchHits = int.Parse(scrollSearch.Body["hits"]["total"].ToString());
searchHits.Count is zero. What may be the cause of this? Also, when I loop into the scrollSearch again, I am expecting that the scrollid would change but it is not changing values.
A size of 2 will return 2 documents in each response, including the first response. So, if the total documents for a given query were less than or equal to 2, all documents would be returned within the first response. Take the following for example
void Main()
{
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var defaultIndex = "messages";
var connectionSettings = new ConnectionSettings(pool)
.DefaultIndex(defaultIndex)
.PrettyJson()
.DisableDirectStreaming()
.OnRequestCompleted(response =>
{
if (response.RequestBodyInBytes != null)
{
Console.WriteLine(
$"{response.HttpMethod} {response.Uri} \n" +
$"{Encoding.UTF8.GetString(response.RequestBodyInBytes)}");
}
else
{
Console.WriteLine($"{response.HttpMethod} {response.Uri}");
}
Console.WriteLine();
if (response.ResponseBodyInBytes != null)
{
Console.WriteLine($"Status: {response.HttpStatusCode}\n" +
$"{Encoding.UTF8.GetString(response.ResponseBodyInBytes)}\n" +
$"{new string('-', 30)}\n");
}
else
{
Console.WriteLine($"Status: {response.HttpStatusCode}\n" +
$"{new string('-', 30)}\n");
}
});
var client = new ElasticClient(connectionSettings);
if (client.IndexExists(defaultIndex).Exists)
{
client.DeleteIndex(defaultIndex);
}
client.IndexMany(new[]
{
new Message { Content = "message 1" },
new Message { Content = "message 2" },
new Message { Content = "message 3" },
new Message { Content = "message 4" },
new Message { Content = "message 5" },
new Message { Content = "message 6" },
});
client.Refresh(defaultIndex);
var searchResponse = client.Search<Message>(s => s
.Scroll("1m")
.Size(2)
.Query(q => q
.Terms(t => t
.Field(f => f.Content.Suffix("keyword"))
.Terms("message 1", "message 2")
)
)
);
searchResponse = client.Scroll<Message>("1m", searchResponse.ScrollId);
}
public class Message
{
public string Content { get; set; }
}
The search and scroll responses return
------------------------------
POST http://localhost:9200/messages/message/_search?pretty=true&scroll=1m
{
"size": 2,
"query": {
"terms": {
"content.keyword": [
"message 1",
"message 2"
]
}
}
}
Status: 200
{
"_scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAADGFnM1SnhtUVdIUmgtM1YyZ2NQei1hZEEAAAAAAAAAxxZzNUp4bVFXSFJoLTNWMmdjUHotYWRBAAAAAAAAAMgWczVKeG1RV0hSaC0zVjJnY1B6LWFkQQAAAAAAAADJFnM1SnhtUVdIUmgtM1YyZ2NQei1hZEEAAAAAAAAAyhZzNUp4bVFXSFJoLTNWMmdjUHotYWRB",
"took" : 4,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.6931472,
"hits" : [
{
"_index" : "messages",
"_type" : "message",
"_id" : "AV8IkTSbM7nzQBTCbQok",
"_score" : 0.6931472,
"_source" : {
"content" : "message 1"
}
},
{
"_index" : "messages",
"_type" : "message",
"_id" : "AV8IkTSbM7nzQBTCbQol",
"_score" : 0.6931472,
"_source" : {
"content" : "message 2"
}
}
]
}
}
------------------------------
POST http://localhost:9200/_search/scroll?pretty=true
{
"scroll": "1m",
"scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAADGFnM1SnhtUVdIUmgtM1YyZ2NQei1hZEEAAAAAAAAAxxZzNUp4bVFXSFJoLTNWMmdjUHotYWRBAAAAAAAAAMgWczVKeG1RV0hSaC0zVjJnY1B6LWFkQQAAAAAAAADJFnM1SnhtUVdIUmgtM1YyZ2NQei1hZEEAAAAAAAAAyhZzNUp4bVFXSFJoLTNWMmdjUHotYWRB"
}
Status: 200
{
"_scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAADGFnM1SnhtUVdIUmgtM1YyZ2NQei1hZEEAAAAAAAAAxxZzNUp4bVFXSFJoLTNWMmdjUHotYWRBAAAAAAAAAMgWczVKeG1RV0hSaC0zVjJnY1B6LWFkQQAAAAAAAADJFnM1SnhtUVdIUmgtM1YyZ2NQei1hZEEAAAAAAAAAyhZzNUp4bVFXSFJoLTNWMmdjUHotYWRB",
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.6931472,
"hits" : [ ]
}
}
------------------------------
Since there are only 2 matching documents for the given query and size was set to 2, both documents are returned in the first response and the following scroll response does not contain any hits.
You can use the total from the initial search response to determine whether you need to call the scroll API for more documents.
The actual _scroll_id value is an implementation detail which may or may not change values on subsequent calls. I would not recommend basing any logic on its value, but only use the _scroll_id value returned from the last scroll response in the subsequent scroll request.

Create Spring Data Aggregation Query with Projection of Nested Array

Here is how my document looks like:
{
"_id" : ObjectId("583cb6bcce047d1e68339b64"),
"variantDetails" : [
{
"variants" : {
"_" : "_"
},
"sku" : "069563-59690"
},
{
"variants" : {
"size" : "35"
},
"sku" : "069563-59690-35",
"barcode" : "809702246941"
},
{
"variants" : {
"size" : "36"
},
"sku" : "069563-59690-36",
"barcode" : "809702246958"
}
......
] }
And I would like to use a complex aggregation query like this:
db.getCollection('product').aggregate([
{ '$match': { 'variantDetails.sku': { '$in': ['069563-59690', '069563-59690-36', '069563-59690-37', '511534-01001'] } } },
{ '$project': {'_id': 1, 'variantDetails': 1, 'variantLength': { '$size': '$variantDetails' } } },
{ '$unwind': '$variantDetails' },
{ '$match': { 'variantDetails.sku': { '$in': ['069563-59690', '069563-59690-36', '069563-59690-37', '511534-01001'] } } },
{ '$match': { '$or': [
{'variantLength': { '$ne': 1 }, 'variantDetails.variants._': { '$ne': '_' } },
{'variantLength': 1 }
] } },
{ '$group': { '_id': '$_id', 'variantDetails': { '$push': '$variantDetails' } } },
{ '$project': {'_id': 1, 'variantDetails.sku': 1, 'variantDetails.barcode': 1} }
])
And here is my java code:
final Aggregation agg = Aggregation.newAggregation(
Aggregation.match(Criteria.where("variantDetails.sku").in(skus)),
Aggregation.project("_id", "variantDetails").and("variantDetails").project("size").as("variantLength"),
Aggregation.unwind("variantDetails"),
Aggregation.match(Criteria.where("variantDetails.sku").in(skus)),
Aggregation.match(new Criteria().orOperator(Criteria.where("variantLength").is(1), Criteria.where("variantLength").ne(1).and("variantDetails.variants._").is("_"))),
Aggregation.group("_id").push("variantDetails").as("variantDetails"),
Aggregation.project("_id", "variantDetails.sku", "variantDetails.barcode")
);
final AggregationResults<Product> result = this.mongo.aggregate(agg, this.mongo.getCollectionName(Product.class), Product.class);
return result.getMappedResults();
The problem is that spring translate
Aggregation.project("_id", "variantDetails.sku", "variantDetails.barcode")
To
{ "$project" : { "_id" : 1 , "sku" : "$variantDetails.sku" , "barcode" : "$variantDetails.barcode"}
But I'm expecting
{ '$project': {'_id': 1, 'variantDetails.sku': 1, 'variantDetails.barcode': 1} }
Could someone let me know how to make it right?
I had the same issue and this way works:
Aggregation.project("_id")
.andExpression("variantDetails.sku").as("variantDetails.sku")
.andExpression("variantDetails.barcode").as("variantDetails.barcode"));
The projection will be:
{'$project': {'_id': 1, 'variantDetails.sku': '$variantDetails.sku',
'variantDetails.barcode': '$variantDetails.barcode'} }
You just need to specify the label as alias in the projection operation as the default that spring provides doesnt match. Use Spring 1.8.5 version
Aggregation.project("_id")
.and(context -> new BasicDBObject("$arrayElemAt", Arrays.asList("variantDetails.sku", 0))).as("variantDetails.sku")
.and(context -> new BasicDBObject("$arrayElemAt", Arrays.asList("variantDetails.barcode", 0))).as("variantDetails.barcode"));
May be an old question, but I faced the same issue pointed by Sean.
If found that if you want the expected result
{ '$project': {'_id': 1, 'variantDetails.sku': 1, 'variantDetails.barcode': 1} }
a solution can be:
Aggregation.project("_id")
.andExpression("1").as("variantDetails.sku")
.andExpression("1").as("variantDetails.barcode")
Virginia León's answer was the starting point for finding this solution

D3 cross tabulation HTML table

I'm trying to create a D3 cross tabulation HTML table (there will be more interactive features, this is just the first step) based on JSON data. I can populate the horizontal table header, but am having trouble with the vertical headers and data fields.
The table should look something like the following:
My code so far (JSFiddle here) is:
var nested = d3.nest()
.key(function(d) { return d._id.env; })
.entries(data.result);
console.log(nested);
var table = d3.select("#table")
.append("table")
.style("border-collapse", "collapse")
.style("border", "2px black solid");
var thead = table.append("thead");
thead.append("tr")
.selectAll("th")
.data(nested)
.enter().append("th")
.text(function(d) { return d.key; });
var tbody = table.append("tbody");
var tr = tbody.selectAll("tr")
.data(nested.values) // not sure how to get this
.enter().append("tr");
tr.selectAll("td")
.data(function(d) { console.log(d); return d; })
.enter().append("td")
.text(function(d, i) { console.log(d[i]); return d; });
The raw data is in the following format:
{
"result" : [
{
"_id" : {
"month" : 5,
"day" : 6,
"year" : 2014,
"env" : "A"
},
"ruleScore" : 83.25,
"jsPerPage" : 12,
"cssPerPage" : 4,
"imagesPerPage" : 7.75
},
{
"_id" : {
"month" : 5,
"day" : 6,
"year" : 2014,
"env" : "B"
},
"ruleScore" : 83,
"jsPerPage" : 12,
"cssPerPage" : 4,
"imagesPerPage" : 10
},
{
"_id" : {
"month" : 5,
"day" : 6,
"year" : 2014,
"env" : "C"
},
"ruleScore" : 83,
"jsPerPage" : 12,
"cssPerPage" : 5,
"imagesPerPage" : 10,
},
{
"_id" : {
"month" : 5,
"day" : 6,
"year" : 2014,
"env" : "D"
},
"ruleScore" : 83.08333333333333,
"jsPerPage" : 12,
"cssPerPage" : 6,
"imagesPerPage" : 9.25
}
],
"ok" : 1
}
I'm guessing this is pretty simple, just can't get my head around it - thanks!

Resources