How to get the document using view in couchbase - couchbase

I have a requirement wherein I have get the document from couchbase.
Following in the Map function that I am using for the same -
function (doc, meta) {
if (meta.type == "json" && doc!=null) {
emit(doc);
}
}
There is no reduce function. Also following is my java code to get the document -
List<URI> hosts = Arrays.asList(
new URI("http://<some DNS with port>/pools")
);
// Name of the Bucket to connect to
String bucket = "Test-Sessions";
// Password of the bucket (empty) string if none
String password = "";
//System.setProperty("viewmode", "development");
// Connect to the Cluster
CouchbaseClient client = new CouchbaseClient(hosts, bucket, password);
String designDoc = "sessions";
String viewName = "by_test";
View view = client.getView(designDoc, viewName);
Query query = new Query();
query.setIncludeDocs(true);
query.setKey(String.valueOf(122));
ViewResponse result = client.query(view, query);
Object object = null;
for(ViewRow row : result) {
if(null != row) {
object = row.getDocument();
}// deal with the document/data
}
System.out.println("Object" + object);
And the data that I have in couchbase is key - "122" and value - "true". But for some reason , I do not get any rows in the ViewResponse. What is going wrong can anyone help?

I don't understand what you are trying to achieve here, you are using a view to get a document by it's key? Key == 122? Why can't you just do client.get(122) ?
If you just need a list of all the keys in your bucket (of which you can use to pull back all documents via include docs) then make your function like so:
function (doc, meta) {
if (meta.type == "json") {
emit();
}
}
The key of the document is always emitted as an ID (viewRow.getId()). You don't need to emit the document, try to emit as little data as possible to keep view sizes small.
If you are needing to manipulate all the documents in your bucket be careful as the size grows, perhaps you'd need to look at pagination to cycle through the results. http://tugdualgrall.blogspot.com.es/
Also once you have the ViewResponse loop over it like so:
for(ViewRow row : result) {
row.getDocument(); // deal with the document/data
}
You don't need to be doing checks for null on the rows.

Related

How to pass variable(&id) from one api to another to fetch corresponding data?

I want to display players stats in listview for which I am consuming this api: https://cricapi.com/api/playerStats?apikey=apikey&pid=pid
Output of above api is:
{
"pid": xxxx,
"profile": "profile description",
"imageURL": "https://www.cricapi.com/playerpic/xxxx.jpg",
pid for each player is retrieved from another api:
https://cricapi.com/api/playerFinder?apikey=apikey&name=playerName
Output of above api is:
{
"data": [
{
"pid": xxxx,
"fullName": "Firstname Lastname",
Currently, I am passing hardcoded pid in first api to display player's stats and code for it is:
FetchJson() async {
var response = await http.get(
'https://cricapi.com/api/playerStats?apikey=apikey&pid=1111');
if (response.statusCode == 200) {
String responseBody = response.body;
var responseJson = jsonDecode(responseBody);
pid = responseJson['pid'];
name = responseJson['name'];
playingRole = responseJson['playingRole'];
battingStyle = responseJson['battingStyle'];
country = responseJson['country'];
imageURL = responseJson['imageURL'];
data = responseJson;
var stats = data['data']['batting'];
var testStats = stats['tests'];
var odiStats = stats['ODIs'];
var tStats = stats['T20Is'];
// T20 Stats
matches_t = tStats['Mat'];
runs_t = tStats['Runs'];
half_t = tStats['50'];
century_t = tStats['100'];
highest_t = tStats['HS'];
avg_t = tStats['Ave'];
And I am calling FetchJson() inside initState().
I tried solution given on my similar / earlier question How to fetch api data by passing variables (parameters)?, but that led me to a different path. I cannot implement that solution, since there's no way for me to return pid through first api that will be received by FetchJson().
My question is:
How to retrieve pid from second api (playerFinder) and feed it to first api (playerStats) and how to make use of that pid so that instead of passing hardcoded pid, I can pass pid as variable and can display multiple players stats in UI?
Required code is here : https://pastebin.com/iU8x9U8z
I want to show players stats in UI but currently I am passing hardcoded playerid which is showing me only one player's stats, but I would like to show different players stats.
**********UPDATE *************
As an alternate solution, I am now using list of pids and parsed those using map and passing them to FetchJson() inside for loop, as below:
var playerIds = [{"pid":35320},{"pid":28114},{"pid":28779},{"pid":28763},{"pid":30176},{"pid":7133},{"pid":5390}]
#override
void initState() {
var intIds = playerIds.map<int>((m) => m['pid'] as int).toList();
for (int i = 0; i < intIds.length; i++) {
FetchJson(intIds[i]);
}
}
FetchJson(int ids) async {
print(ids);
var response = await http.get(
'https://cricapi.com/api/playerStats?apikey=apikey&pid=$ids');
....
}
The issue I am now facing with this approach is, its taking last pid from the list and displaying its data in UI repeatedly. The expected output I want to see is: players data for all pids in UI and I am not sure how to achieve this.
Complete referenced code here: https://pastebin.com/kFYBfHuf
One answer is to create Maps from both sets of api's down to desirable player data then use a switch statement as written below similar to a where clause in order to identify matching data.
The big problem is that you need to identify matching data items in both api's. In my example I've assumed it may be a players name or it could be their team and team number, but there has to be something that validates you are looking at differing data points for the same player.
switch(variable_expression) {
case name = full_name: {
// statements;
}
break;
case constant_expr2: {
//statements;
}
break;
default: {
//statements;
}
break;
}

How to prevent format change of date in view after save in ASP MVC

After saving DateTime in controller, I pass it back to the View but when it's displayed in view the value became /Date(1545062400000)/.
I already checked in the controller while in process if the data was changed but it did not since I'm just passing the viewmodel in the view.
[HttpPost]
public ActionResult UpdateHeader(RecordViewModel recordViewModel)
{
var ResultMessage = "";
if (ModelState.IsValid)
{
Record record = (from c in context.Records
where c.RecordId == recordViewModel.RecordId
select c).FirstOrDefault();
if (record == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
record.Description = recordViewModel.Description;
record.Date = recordViewModel.Date;
record.Remarks = recordViewModel.Remarks;
try
{
context.SaveChanges();
ResultMessage = "Record successfully updated.";
}
catch (Exception ex)
{
ModelState.AddModelError("", ErrorHelper.GetInnerException(ex));
ResultMessage = "Error: " + ErrorHelper.GetInnerException(ex);
}
}
var result = new { Model = recordViewModel, ResultMessage = ResultMessage };
return Json(result, JsonRequestBehavior.AllowGet);
}
Angular
self.submitEdit = function () {
var updateRecordHeader = RecordServices.updateRecordHeader(self.header)
.then(function successCallback(response) {
self.header = response.data.Model;
self.header.ResultMessage = response.data.ResultMessage;
}, function errorCallback(response) { toastr.error(response.statusText); });
}
The /Date(1545062400000)/ is known as date ticks using UNIX timestamp format since RFC7519 "epoch" (January 01, 1970), which cannot be directly consumed as JS Date object without converting it first. The reason behind usage of the ticks is JSON format doesn't have specific representation for DateTime struct when serialized to plain strings (see this reference).
You can create a custom function to convert ticks into JS Date object:
function toJSDate(value) {
var regex = /Date\(([^)]+)\)/;
var results = regex.exec(value);
var date = new Date(parseFloat(results[1])); // or parseInt
return date;
}
Or even simpler without regex by picking numeric values directly like this:
function toJSDate(value) {
var date = new Date(parseFloat(value.substring(6))); // or parseInt
return date;
}
Then use that function for ticks-to-date conversion:
// example
var header = response.data.Model;
var dateObject = toJSDate(header.Date);
// assign date object afterwards
Note that you may need to create another object structure which resembles response.data.Model but using server-side Date property with JS date object.
As an alternative you may create a getter-only string property which uses ToString() to convert DateTime value into desired string representation, then use it inside JS.
Side note:
Avoid using viewmodel property name which exactly matches built-in JS function names & objects (i.e. Date) for clarity.
Related issues:
How do I format a Microsoft JSON date?
Converting .NET DateTime to JSON

Storing JSON data as columns in Azure table storage

How do a format my json data and/or change my function so that it gets stored as columns in Azure table storage?
I am sending a json string to the IoT hub:
{"ts":"2017-03-31T02:14:36.426Z","timeToConnect":"78","batLevel":"83.52","vbat":"3.94"}
I run the sample function (in the Azure Function App module) to transfer the data from the IoT hub into my storage account:
'use strict';
// This function is triggered each time a message is revieved in the IoTHub.
// The message payload is persisted in an Azure Storage Table
var moment = require('moment');
module.exports = function (context, iotHubMessage) {
context.log('Message received: ' + JSON.stringify(iotHubMessage));
context.bindings.deviceData = {
"partitionKey": moment.utc().format('YYYYMMDD'),
"rowKey": moment.utc().format('hhmmss') + process.hrtime()[1] + '',
"message": JSON.stringify(iotHubMessage)
};
context.done();
};
But in my storage table, it shows up as a single string rather than getting split into columns (as seen in the storage explorer.
How do I get it into columns for ts, timeToConnect, batLevel, and vbat?
In case anyone is looking for a solution in c#:
private static async Task ProcessMessage(string message, DateTime enqueuedTime)
{
var deviceData = JsonConvert.DeserializeObject<JObject>(message);
var dynamicTableEntity = new DynamicTableEntity();
dynamicTableEntity.RowKey = enqueuedTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
foreach (KeyValuePair<string, JToken> keyValuePair in deviceData)
{
if (keyValuePair.Key.Equals("MyPartitionKey"))
{
dynamicTableEntity.PartitionKey = keyValuePair.Value.ToString();
}
else if (keyValuePair.Key.Equals("Timestamp")) // if you are using a parameter "Timestamp" it has to be stored in a column named differently because the column "Timestamp" will automatically be filled when adding a line to table storage
{
dynamicTableEntity.Properties.Add("MyTimestamp", EntityProperty.CreateEntityPropertyFromObject(keyValuePair.Value));
}
else
{
dynamicTableEntity.Properties.Add(keyValuePair.Key, EntityProperty.CreateEntityPropertyFromObject(keyValuePair.Value));
}
}
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("myStorageConnectionString");
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference("myTableName");
table.CreateIfNotExists();
var tableOperation = TableOperation.Insert(dynamicTableEntity);
await table.ExecuteAsync(tableOperation);
}
How do I get it into columns for ts, timeToConnect, batLevel, and
vbat?
To get these attributes as separate columns in table, you would need to defalte the object and store them separately (currently you are just converting the entire object into string and storing that string).
Please try the following code:
module.exports = function (context, iotHubMessage) {
context.log('Message received: ' + JSON.stringify(iotHubMessage));
var deviceData = {
"partitionKey": moment.utc().format('YYYYMMDD'),
"rowKey": moment.utc().format('hhmmss') + process.hrtime()[1] + '',
};
Object.keys(iotHubMessage).forEach(function(key) {
deviceData[key] = iotHubMessage[key];
});
context.bindings.deviceData = deviceData;
context.done();
};
Please note that I have not tried to execute this code so it may contain some errors.

Get only values from rows and associations with Sequelize

I am using Sequelize, MySQL and Node to write a web application.
For most of my DB needs, I usually do some verification, then fetch my models (eagerly with associations) and send them back to the client, almost always as-is (at least, up to now).
I wrote a little utility function getValuesFromRows to extract the values from a returned row array:
getValuesFromRows: function(rows, valuesProp) {
// get POD (plain old data) values
valuesProp = valuesProp || 'values';
if (rows instanceof Array) {
var allValues = [];
for (var i = 0; i < rows.length; ++i) {
allValues[i] = rows[i][valuesProp];
}
return allValues;
}
else if (rows) {
// only one object
return rows[valuesProp];
}
return null;
}
// ...
...findAll(...)...complete(function(err, rows) {
var allValues = getValuesFromRows(rows);
sendToClient(errToString(err, user), allValues);
});
However, I am adding more and more complex relations to my DB models. As a result, I get more associations that I have to fetch. Now, I don't only have to call above function to get the values from each row, but also I need more complicated utilities to get the values from all included (eagerly loaded) associations. Is there a way to only get values from Sequelize queries (and not the Sequelize model instance) that also includes all associated values from the instance?
Else, I would have to manually "get all values from each Project and add one item to that values object for the values property of each entry of Project.members" (for example). Note that things get worse fast if you nest associations (e.g. members have tasks and tasks have this and that etc.).
I am guessing that I have to write such utility myself?
I found a simple solution to my problem, by extending my existing POD converting function above with a recursion into all include'd associations of the query. The Solution works with find, findAll, all and possibly other operations with non-trivial results.
Code
/**
* Get POD (plain old data) values from Sequelize results.
*
* #param rows The result object or array from a Sequelize query's `success` or `complete` operation.
* #param associations The `include` parameter of the Sequelize query.
*/
getValuesFromRows: function(rows, associations) {
// get POD (plain old data) values
var values;
if (rows instanceof Array) {
// call this method on every element of the given array of rows
values = [];
for (var i = 0; i < rows.length; ++i) {
// recurse
values[i] = this.getValuesFromRows(rows[i], associations);
}
}
else if (rows) {
// only one row
values = rows.dataValues;
// get values from associated rows
if (values && associations) {
for (var i = 0; i < associations.length; ++i) {
var association = associations[i];
var propName = association.as;
// recurse
values[propName] = this.getValuesFromRows(values[propName], association.include);
};
}
}
return values;
}
Example
var postAssociations = [
// poster association
{
model: User,
as: 'author'
},
// comments association
{
model: Comment,
as: 'comments',
include: [
{
// author association
model: User,
as: 'author'
}
]
}
];
// ...
var query = {
where: ...
include: postAssociations;
};
// query post data from DB
return Post.findAll(query)
// convert Sequelize result to POD
.then(function(posts) {
return getValuesFromRows(posts, postAssociations);
})
// send POD back to client
.then(client.sendPosts);
In the above example, client.sendPosts receives an array. Each entry of the array will have properties author and comments. Each comment in the comments array will also have an author property. The entire array only contains POD (plain old data).

Recursive search for sites using Client Object Model using Site Id (GUID)

Using the Client Object Model I am looking for the most efficient way to search a SharePoint server and determine if a specific subsite exists given its unique ID (GUID). We are storing the GUID in our external system because we need to get back to the site and the GUID is the only property that can not change. I know that CAML can be used to search for data within a specific site. However, I haven't been able to find an API that will do this for subsites. I am forced to do a recursive search and use a for loop. In my case, we could have thousands of sites nested on our server.
This logic does one level -- but is not efficient when thousands of subsites exists.
public bool SiteExists(ClientContext context, string myGuid)
{
Web oWebsite = context.Web;
context.Load(oWebsite, website => website.Webs, website => website.Title, website => website.Description, website => website.Id);
context.ExecuteQuery();
for (int i = 0; i != oWebsite.Webs.Count; i++)
{
if (String.Compare(oWebsite.Webs[i].Id.ToString(), myGuid, true) == 0)
{
return true;
}
}
return false;
}
public bool SiteExists(ClientContext context, string myGuid) {
Guid id = new Guid(myGuid);
Site site = context.Site;
Web foundWeb = site.OpenWebById(id);
context.Load(foundWeb);
context.ExecuteQuery();
if(foundWeb != null) {
return true;
}
return false;
}