Azure Cosmos DB add related entities to the query result - azure

In my cosmos DB collection I have entities of such type:
// Suppliers:
[{
"id": "some_unique_str",
"products": [
"id_of_product1",
"id_of_product2"
]
}]
// Products:
[{
"id": "id_of_product1",
"name": "product name"
},
//...
]
I need to write a query to get such result:
[{
"id": "some_unique_str",
"products": [
{
"id": "id_of_product1",
"name": "product 1 name"
},
{
"id": "id_of_product2",
"name": "product 2 name"
}
]
}]
In other words: I'm trying to achieve OData expand functionality.
Is it possible?

You can't achieve that with direct sql in cosmos db sql api. Your needs can be implemented with foreign key in relational database,not no-sql database.
In cosmos db sql api,you could achieve that with stored procedure.I tried to write some code for your reference:
function sample(prefix) {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT c.id,c.products FROM c where is_defined(c.products)',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) {
var response = getContext().getResponse();
response.setBody('no docs found');
}
else {
var response = getContext().getResponse();
var returnArray = [];
for (var i=0;i<feed.length;i++){
var map = {};
map['id'] = feed[i].id;
mergeData(map,feed[i].products);
returnArray.push(map);
}
response.setBody(returnArray);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
function mergeData(map,idArray){
var sqlQuery = {
"query": 'SELECT c.id,c.name FROM c where not is_defined(c.products) and '+
' array_contains( #idArray,c.id,true) ',
"parameters": [
{"name": "#idArray", "value": idArray}
]
}
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
sqlQuery,
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) {
map['products'] = [];
}
else {
map['products'] = feed;
}
});
}
}
Output with your sample data is:

Related

query Azure Cosmos DB to return no duplicates

I have an Azure Cosmos DB with the following document below.
In this, the person with email jim#test.com has 3 roles, how can I query this to return a list comprising the email plus the 3 roles?
All I have just now is the following but that returns duplicate email addresses.
SELECT c.Email, o.RoleDesc
FROM c
JOIN o IN c.OrgRoles
WHERE c.Email = "jim#test.com"
{
"id": "23452345234",
"Email": "jim#test.com",
"OrgRoles": [
{
"RoleID": "234234",
"RoleDesc": "worker"
},
{
"RoleID": "345678",
"RoleDesc": "Manager"
},
{
"RoleID": "456433",
"RoleDesc": "Admin"
}
],
"DeviceIDs": [
{
"Device": "ABC-12312"
},
{
"Device": "DEF-76576"
}
],
"UpdatedDate": "01-12-17",
"CreatedDate": "01-11-17",
"_rid": "KFokAIrg-QABAAAAAAAAAA==",
"_self": "dbs/KFokAA==/colls/KFokAIrg-QA=/docs/KFokAIrg-QABAAAAAAAAAA==/",
"_etag": "\"00002d00-0000-0000-0000-59ef0f7f0000\"",
"_attachments": "attachments/",
"_ts": 1508839295
}
You need a user-defined function to do this. Register:
function getEmailAndRoles(doc) {
var result = { Email: doc.Email }
result.Roles = []
for(idx = 0; idx < doc.OrgRoles.length; idx++) {
result.Roles.push(doc.OrgRoles[idx].RoleDesc)
}
return result;
}
Then call
SELECT udf.getEmailAndRoles(c)
FROM c
WHERE c.Email = "jim#test.com"

Finding a subdoc by id with Mongoose

I am trying to find and update a subdoc using mongoose and mongdb but I can't seem to find the subdocs using the ids.
My schema
var Attending = new Schema({
users: []
});
var Query = new Schema({
name: [],
url: [],
attending: [Attending],
img: []
});
Using the ids for both docs, just finding returns null for the doc. However, if i only using the general Id I can find the entire doc but not the subdoc.
Queries.findOne(
{ "_id": queryId, "attending._id": attendingId },
function(err, doc) {
if (err) throw err;
console.log(doc);
res.render('index');
}
);
sample doc
{
"_id": {
"$oid": "58d995026d7c8f0a3028a50f"
},
"img": [
"https://pic1",
"https://pic2"
],
"attending": [
{
"_id": {
"$oid": "58d995026d7c8f0a3028a505"
},
"users": [
"somebody"
]
},
{
"_id": {
"$oid": "58d995026d7c8f0a3028a506"
},
"users": [
"another person"
]
}
],
"url": [
"https://www.yelp.com/2",
"https://www.yelp.com/1"
],
"name": [
"The Rivermill",
"Sharkeys"
],
"__v": 0
}
I am using the correct ids and expect to the first subdoc in attending to be returned or whichever one is searched. Instead null is returned.
Queries is made like this:
var names = [];
var urls = [];
var imgUrls = [];
var attendingArray = [];
for (var i=0; i<10; i++) {
names.push(businesses[i].name);
urls.push(businesses[i].url);
imgUrls.push(businesses[i].image_url);
//add attending schema
var newAttending = Attending({
users: ["somebody"]
});
attendingArray.push(newAttending);
}
var newQuery = Queries({
name: names,
url: urls,
attending: attendingArray,
img: imgUrls
});

Mongo + check multiple fields existing

I am working mongo with nodejs.
I have array list:
var checkFields = ["field1","field2","field3"];
I try to get the count of records having the array list fields and user field is equal to admin.
Sample data:
[
{
"checkFields": {
"field1": "00124b3a5c31",
"user": "admin"
}
},
{
"checkFields": {
"field2": "00124b3a5c31",
"user": "admin"
}
},
{
"checkFields": {
"field1": "00124b3a5c31",
"user": "regular"
}
}
]
Query:
db.collection_name.find(
{"checkFields.user" : "admin"}
{ "checkFields.field1": { $exists: true} }
)
Expected Result:
Result is to get rows of count of matching the field in array list(checkFields).
Building up an $or array for the list of field existence checks is the right approach, but assuming you're on a current node.js build you can simplify the query creation to:
var checkFieldsLists = checkFields.map(field => ({
['checkFields.' + field]: {$exists: true}
}));
var query = {
$or: checkFieldsLists,
'checkFields.user': 'admin'
}
This removes the superfluous $or for the "user is admin" check which lets you also remove the outer $and, so that the generated query is:
{ '$or':
[ { 'checkFields.field1': { '$exists': true } },
{ 'checkFields.field2': { '$exists': true } },
{ 'checkFields.field3': { '$exists': true } } ],
'checkFields.user': 'admin' }
I tried the following code. Its working but don't know its good solution and perfomance. Please anyone have better answer means please post it.
var checkFields = ["field1", "field2", "field3"];
var checkFieldsLists = [];
for ( i = 0; i < checkFields.length; i++) {
var jsObj = {};
jsObj['checkFields.' + checkFields[i]] = {};
jsObj['checkFields.' + checkFields[i]].$exists = true;
checkFieldsLists.push(jsObj);
}
var query = {
"$and" : [{
"$or" : checkFieldsLists
}, {
"$or" : [{
"checkFields.user" : "admin"
}]
}]
};
console.log(JSON.stringify(query));
//console log will return
/*
{"$and":[{
"$or" : [{
"checkFields.field1" : {
"$exists" : true
}
}, {
"checkFields.field2" : {
"$exists" : true
}
}, {
"checkFields.field3" : {
"$exists" : true
}
}]
}, {
"$or" : [{
"checkFields.user" : "admin"
}]
}]
}
*/
collection.find(query);
Here is the solution using aggregate query.
var Db = require('mongodb').Db, Server = require('mongodb').Server, assert = require('assert');
var db = new Db('localhost', new Server('localhost', 27017));
var checkFields = ["field1", "field2", "field3"];
var checkFieldsLists = [];
for (var i = 0; i < checkFields.length; i++) {
var jsObj = {};
jsObj['checkFields.' + checkFields[i]] = {};
jsObj['checkFields.' + checkFields[i]].$exists = true;
checkFieldsLists.push(jsObj);
}
var query = {
"$and" : [{
"$or" : checkFieldsLists
}, {
"$or" : [{
"checkFields.user" : "admin"
}]
}]
};
var matchQuery = {
"$match" : {
"checkFields.user" : "admin",
"$or" : checkFieldsLists
}
};
var groupQuery = {
$group : {
_id : null,
count : {
$sum : 1
}
}
};
var aggregateCheckFields = function(db, callback) {
console.log("Match query is ====>" + JSON.stringify(matchQuery));
console.log("Group query is ====>" + JSON.stringify(matchQuery));
db.collection('checkfields').aggregate([ matchQuery, groupQuery ]).toArray(
function(err, result) {
assert.equal(err, null);
console.log("Result is ===>" + JSON.stringify(result));
if (result.length > 0) {
console.log("Count is ===>" + result[0].count);
}
callback(result);
});
};
db.open(function(err, db) {
aggregateCheckFields(db, function() {
db.close();
});
});
Output:-
Result is ===>[{"_id":null,"count":3}]
Count is ===>3

update parent child data nodejs mongodb

I am new in mongodb with nodejs.I want to update the comments data.Here is my document
{
"__v": NumberInt(0),
"_id": ObjectId("565443b1172e19d51f98b0ed"),
"address": "tohana",
"comments": [
{
"_id": ObjectId("5654455fe088d89c20736e3c"),
"comment": "good man",
"uemail": "dinesh#gmail.com",
"uname": "dinesh"
},
{
"_id": ObjectId("565445e471dce6ca20705a84"),
"comment": "nice person",
"uemail": "kr#gmail.com",
"uname": "krishan"
},
{
"_id": ObjectId("5654460e7aa73bec2064060e"),
"comment": "bad person",
"uemail": "Rai",
"uname": "Rahul"
}
],
"email": "nishantg#ocodewire.com"▼,
"name": "Nishant"
}
I am using Angular js in frontend and nodeJs as backend. Here is my code:
app.post('/commentsSave/:id', function(req, res) {
var id = req.params.id; // userId
var input = JSON.parse(JSON.stringify(req.body)); //commentData
var commentId = input.id; //commentId
var name = input.name;
var email = input.email;
var comment = input.comment
res.send({data:id,data2:input});
})
app.post('/commentsSave/:id', function(req, res) {
var id = req.params.id; // userId
var input = JSON.parse(JSON.stringify(req.body)); //commentData
var commentId = input.id; //commentId
var name = input.name;
var email = input.email;
var comment = input.comment
Users.update({'comments._id': input.id},
{
$set: {
'comments.$.name': name,
'comments.$.email': email,
'comments.$.comment': comment
}
},function(error, result){
if(error){
console.log(error);
}
else{
console.log(result);
}
})
}

DynamoDB putitem in NodeJs - arrays of objects

I'm trying to set up a small api from AWS Lambda to DynamoDB and I am having trouble figuring out if and how I can write an array of objects into a key.
I have an object like
{
"teamName": "Team Awesome",
"members": [
{
"email": "person-1#example.com",
"name": "Bob"
},
{
"email": "person-2#example.com",
"name": "Alice"
}
]
}
The members array is giving me issues, in the docs it looks like it can be done considering the list types, but there is just no example how HOW to do it, and I am running out of ways to try it.
So is it possible to write something in this format at all and how do you in that case do it?
Example code - what do I put at ???
var AWS = require('aws-sdk');
var dynamodb = new AWS.DynamoDB();
exports.handler = function(event, context) {
var tableName = "GDCCompetition";
var datetime = new Date().getTime().toString();
DynamoDB.putItem({
"TableName": tableName,
"Item": {
"datetime": {
"N": datetime
},
"teamName": {
"S": event.teamName
},
"members": ???
}
});
}
The documentation is not really obvious, but there is a thing called DocClient, you can pass a usual JS object to it and it will do all the parsing and transformation into AWS object (with all the types). You can use it like this:
var AWS = require("aws-sdk");
var DynamoDB = new AWS.DynamoDB.DocumentClient();
var params = {
TableName: "MyTable",
Item: {
"teamName": "Team Awesome",
"members": [
{
"email": "person-1#example.com",
"name": "Bob"
},
{
"email": "person-2#example.com",
"name": "Alice"
}
]
}
};
DynamoDB.put(params, function (err) {
if (err) {
return throw err;
}
//this is put
});
You could convert the object to DynamoDb record first
const AWS = require('aws-sdk');
var tableName = "GDCCompetition";
var datetime = new Date().getTime().toString();
const members = [
{
"email": "person-1#example.com",
"name": "Bob"
},
{
"email": "person-2#example.com",
"name": "Alice"
}
];
const marshalled = AWS.DynamoDB.Converter.marshall({ members });
const params = {
"TableName": tableName,
"Item": {
"datetime": {
"N": datetime
},
"teamName": {
"S": event.teamName
},
"members": marshalled.members,
},
}
AWS.DynamoDB.putItem(params, function (err) {
if (err) {
return throw err;
}
});

Resources