How to display the position within an array with Cosmos DB SQL - json

I have a problem attempting to select from a document array in Cosmos-db. (SQL-api)
I am able to select the values from the array however I would like to be able to display each of the values position within the array also.
Sample JSON document:
{
"Type": "SampleJSONMessage",
"Version": "1",
"Reference": "Test",
"DateTime": "2019-03-29T15:16:11.503Z",
"Configuration": {
"MessageType": "1",
"MessageConfig": "100",
"Source": [
{
"Source": "Stream1"
},
{
"Source": "Stream2"
},
{
"Source": "Stream3"
},
{
"Source": "Stream4"
}
]
}
}
I execute this:
select c.Configuration.Source from c
which returns this:
[
{
"Source": "Stream1"
},
{
"Source": "Stream2"
},
{
"Source": "Stream3"
},
{
"Source": "Stream4"
}
]
This is what I would like to display:
[
{
"Source": "Stream1" ,
"Position": "1"
},
{
"Source": "Stream2",
"Position": "2"
},
{
"Source": "Stream3",
"Position": "3"
},
{
"Source": "Stream4",
"Position": "4"
}
]
Any help appreciated!

While a specific index is stored inside CosmosDB for each array element, the SQL API doesn't currently have a method for accessing it directly. A user defined function will work though.
Here is the UDF I added to my collection:
function ADD_INDEX(array){
array.forEach(function(item, index){item.Position = index.toString()});
return array;
}
And the modified query to use this to get the output you want:
select udf.ADD_INDEX(c.Configuration.Source) AS Source from c

Related

Merge Json Array Nodes and roll up a child element

I have a requirement to roll a collection of nodes that uses the current node name (within the collection) and for the value take each child nodes value (single node) into a string array, then use the parents key as the key.
Given.
{
"client": {
"addresses": [
{
"id": "27ef465ef60d2705",
"type": "RegisteredOfficeAddress"
},
{
"id": "b7affb035be3f984",
"type": "PlaceOfBusiness"
},
{
"id": "a8a3bef166141206",
"type": "EmailAddress"
}
],
"links": [
{
"id": "29a9de859e70799e",
"type": "Director",
"name": "Bob the Builder"
},
{
"id": "22493ad4c4fd8ac5",
"type": "Secretary",
"name": "Jennifer"
}
],
"Names": [
{
"id": "53977967eadfffcd",
"type": "EntityName",
"name": "Banjo"
}
]
}
}
from this the output needs to be
{
"client": {
"addresses": [
"RegisteredOfficeAddress",
"PlaceOfBusiness",
"EmailAddress"
],
"links": [
"Director",
"Secretary"
],
"Names": [
"EntityName"
]
}
}
What is the best way to achieve this? Any pointers to what/how to do this would be greatly appreciated.
Ron.
You can iterate over entries of your client object first with the help of the $each function, then get types for each of them, and combine via $merge:
{
"client": client
~> $each(function($list, $key) {{ $key: $list.type }})
~> $merge
}
Live playground: https://stedi.link/OpuRdE9

Getting all subitems from all documents with a Couchbase map/reduce view

I have Couchbase documents with structure like this:
{
"subscriberIds": [
{
"type": "END_USER",
"identity": "00000000223"
}
],
"userDataId": "SUB-00000000223",
"status": "ACTIVATED",
"subscriptions": [
{
"id": "Something1",
"attributes": [
{
"value": "Active",
"name": "Status"
}
],
"priority": "1",
"subscriptionStartDate": somedate,
"productShortName": "Something1"
},
{
"id": "Something2",
"attributes": [
{
"value": "Active",
"name": "Status"
}
],
"priority": "1",
"subscriptionStartDate": somedate,
"productShortName": "Something2"
}
],
}
And I'm trying to write a view to get all the 'subscriptions' from all documents in bucket as:
{"total_rows":900,"rows":[
{"id":"Something1","key":null,"value":"00000000223"},
{"id":"Something2","key":null,"value":"00000000223"},
...
but, I can't get nested item from doc
function (doc, meta) {
for (var i in doc.subscriptions) {
emit(doc.subscriptions.id, doc.id);
}
}
I know this is possible, but apparently I do not fully understand the concept of views.
for (var i in doc.subscriptions) {
emit(doc.subscriptions[i].id, doc.id);
}

lodash sort an array of objects by a property which has an array of objects

I have a an object. I am able to sort the items by using lodash's _.orderBy().
However, in one of the scenario I have to sort by subject, which is an array of objects. Items inside the subject array are already sorted based on the name.
As subject is an array of the objects, I need to consider the first item for sorting.
[
{
"id": "1",
"name": "peter",
"subject": [
{
"id": "1",
"name": "maths"
},
{
"id": "2",
"name": "social"
}
]
},
{
"id": "2",
"name": "david",
"subject": [
{
"id": "2",
"name": "physics"
},
{
"id": "3",
"name": "science"
}
]
},
{
"id": "3",
"name": "Justin",
"subject": [
]
}
]
You can use _.get() to extract the name (or id) of the 1st item in subjects. If no item exists, _.get() will return undefined, which can be replaced with a default value. In this case, we don't want to use an empty string as a default value, since the order would change. Instead I'm checking if the value is a string, if it is I use lower case on it, if not I return it as is.
const arr = [{"id":"1","name":"peter","subject":[{"id":"1","name":"maths"},{"id":"2","name":"social"}]},{"id":"2","name":"david","subject":[{"id":"2","name":"physics"},{"id":"3","name":"science"}]},{"id":"3","name":"Justin","subject":[]}]
const result = _.orderBy(arr, o => {
const name = _.get(o, 'subject[0].name')
return _.isString(name) ? name.toLowerCase() : name
})
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
Use _.sortBy with a comparison/sorting function argument. Your function itself can look into the receiving arguments subject key (I think its the subject you want to compare?)
Since you have the question also tagged with ES6 here is an JS only solution via Array.sort:
let arr = [ { "id": "1", "name": "peter", "subject": [ { "id": "1", "name": "maths" }, { "id": "2", "name": "social" } ] }, { "id": "2", "name": "david", "subject": [ { "id": "2", "name": "physics" }, { "id": "3", "name": "science" } ] }, { "id": "3", "name": "Justin", "subject": [] }, ]
const result = arr.sort((a,b) =>
a.subject.length && b.subject.length
? a.subject[0].name.localeCompare(b.subject[0].name)
: a.subject.length ? -1 : 1)
console.log(result)

Correct way to loop through an JSON object [duplicate]

This question already has answers here:
Unable to iterate through JSON array
(3 answers)
Closed 6 years ago.
Since there seems nobody is able to find a solution for my problem, I would like to ask my question in a different way:
What should be the correct way to loop through the games section of the following object:
[
{
"_id": "5710b0ddab8b724011705037",
"username": "test",
"name": "testuser",
"__v": 0,
"library": {
"games": [
{
"platform": [
"17",
"94"
],
"name": "Simcity",
"id": "37620"
},
{
"platform": [
"146",
"20"
],
"name": "destiny",
"id": "36067"
}
],
"platforms": [
{
"name": "Xbox360",
"id": "20"
},
{
"name": "PC",
"id": "94"
}
]
}
}
]
This object is fetched out through mongoose out of a MongoDB, all happens in the API section of my NodeJS application:
.get('/test', function(req, res){
User.findOne({"username": req.decoded.username}, function(err, user){
// trying to loop here
});
})
I have tried everything I find, but I cannot get it to work, so I wonder what ways you use to do this, without cluttering your vision with my (maybe wrong) ways and errors...
Use for...in to loop through Javascript/JSON objects
for (variable in object) {...
}
for...in documentation
Use forEach to loop through Javascript/JSON arrays
arr.forEach(callback[, thisArg])
forEach documentation
Updated Answer:
Your edit markedly changes the structure of the data compared to your original question.
Now, you have an array containing one entry, which has library, which has games, so you reference it (assuming user points to the whole thing) as user[0].library.games. E.g.:
user[0].library.games.forEach(function(entry) {
// Use `entry` here
});
var user = [{
"_id": "5710b0ddab8b724011705037",
"username": "test",
"name": "testuser",
"__v": 0,
"library": {
"games": [{
"platform": [
"17",
"94"
],
"name": "Simcity",
"id": "37620"
}, {
"platform": [
"146",
"20"
],
"name": "destiny",
"id": "36067"
}],
"platforms": [{
"name": "Xbox360",
"id": "20"
}, {
"name": "PC",
"id": "94"
}]
}
}];
user[0].library.games.forEach(function(entry) {
log(entry.name);
});
function log(msg) {
var p = document.createElement('p');
p.appendChild(document.createTextNode(msg));
document.body.appendChild(p);
}
Original Answer:
games is an array, assuming you have o referencing that object, you can reference it from o.user.library.games.
There are lots of ways to loop over arrays (see this answer for a list); one of them is forEach:
o.user.library.games.forEach(function(entry) {
// Use `entry` here, e.g. `entry.name`, `entry.id`, etc.
});
E.g.:
var o = {
"user": {
"name": "testuser",
"library": {
"platforms": [{
"id": "20",
"name": "Xbox360"
}, {
"id": "94",
"name": "PC"
}],
"games": [{
"id": "37620",
"name": "Simcity",
"platform": [
"17",
"94"
]
}, {
"id": "36067",
"name": "destiny",
"platform": [
"146",
"Xbox360"
]
}]
}
}
};
o.user.library.games.forEach(function(entry) {
log(entry.name);
});
function log(msg) {
var p = document.createElement('p');
p.appendChild(document.createTextNode(msg));
document.body.appendChild(p);
}
From your comment below, it sounds like the structure may not be quite as you quoted it in the question. You can use node-inspector to debug your NodeJS code, set a breakpoint at the beginning of where you want to loop, and inspect the variable you have referring to the object. That will show you its structure. It's very easy to install (npm install -g node-inspector) and use (node-debug your-main-file.js).

Linq to Json using Like Clause

I've got an MVC 3 web app and am returning a JSON object which I would like to use Linq against to limit the result returned to the client jquery.
The Json response takes the following structure:
{
"Data": {
"Items": [
{
"Result": {
"Id": "e2ba4912-c387-4f54-b55e-06742a6858db",
"Name": "SomeOtherSetting",
"Value": "500",
"Archived": false
},
"Result": {
"Id": "17c27584-cea8-42c2-b6c4-0b30625ac3ce",
"Name": "Setting2",
"Value": "600",
"Archived": false
},
"Result": {
"Id": "17c27584-cea8-42c2-b6c4-0b30625ac3ce",
"Name": "Setting3",
"Value": "700",
"Archived": false
}
}]
}
}
....
I need to return or grab just the json items that have a Name like 'Setting' for example. In the example, this would return just the 2 Json nodes.
My Linq is very limited and what I have is: Settings is where the Json response is stored.
NewtonSoft.Json.Linq.JObject data = NewtonSoft.Json.Linq.JObject.Parse(Settings);
var result = from p in data["Data"]["Items"].Children()
where (p["Result"]["Name"].Contains("Expenses.Help.Tip"))
select new { Name = (string)p["Result"]["Name"], Value = (string)p["Result"]["Value"] };
When I run this I get nothing in my result. Can anyone help and tell me what I'm doing wrong?
Thanks.
Well, I'm not a Json specialist, but I think your Json structure has some problems.
I tried an online parser, and parsing took only the third result... (try to copy past your code in the left window, and look at JS eval.
Instead of
"Items": [
{
"Result": {
},
"Result": {
},
"Result": {
}
}]
you should have each element of Items array (each 'Result') into {}.
"Items": [
{
{"Result": {
}
},
{"Result": {
}
},
{"Result": {
}
}]
I got it to work by changing your Json file to
{
"Data": {
"Items": [
{
"Result": {
"Id": "e2ba4912-c387-4f54-b55e-06742a6858db",
"Name": "SomeOtherSetting",
"Value": "500",
"Archived": false
}
},
{
"Result": {
"Id": "17c27584-cea8-42c2-b6c4-0b30625ac3ce",
"Name": "Setting2",
"Value": "600",
"Archived": false
}
},
{
"Result": {
"Id": "17c27584-cea8-42c2-b6c4-0b30625ac3ce",
"Name": "Setting3",
"Value": "700",
"Archived": false
}
}]
}
}
using
var data = JObject.Parse(test)["Data"]["Items"].Children()
.Where(m => m["Result"]["Name"].Value<string>().Contains("Setting"))
.Select(m => new
{
Name = m["Result"]["Name"].Value<string>(),
Value = m["Result"]["Value"].Value<int>()
})
.ToList();