How to find matching datas from two json documents in couchdb? - javascript

How to find matching datas from two json documents.For ex: I have two json documents and skills json documents.
In Skills Document:
{
"_id": "b013dcf12d1f7d333467b1447a00013a",
"_rev": "3-e54ad6a14046f809e6da872294939f12",
"core_skills": [
{
"core_skill_code": "SA1",
"core_skill_desc": "communicate with others in writing"
},
{
"core_skill_code": "SA2",
"core_skill_desc": "complete accurate well written work with attention to detail"
},
{
"core_skill_code": "SA3",
"core_skill_desc": "follow guidelines/procedures/rules and service level agreements"
},
{
"core_skill_code": "SA4",
"core_skill_desc": "ask for clarification and advice from others"
}
]}
In Employee Document:
{
"_id": "b013dcf12d1f7d333467b12350007op",
"_rev": "3-e54ad6a14046f809e6da156794939f12",
"employee_name" :"Ashwin",
"employee_role" : "Software engineer",
"core_skills":["SA1","SA4"]
}

I have no idea what you want to do, but the following might be helpful. Assuming that the first data set is a list of skills and their descriptions and the second is an employee record, then assigning to variables with suitable names might look like:
var skillCodes = {
"_id": "b013dcf12d1f7d333467b1447a00013a",
"_rev": "3-e54ad6a14046f809e6da872294939f12",
"core_skills": [{
"core_skill_code": "SA1",
"core_skill_desc": "communicate with others in writing"
},{
"core_skill_code": "SA2",
"core_skill_desc": "complete accurate well written work with attention to detail"
},{
"core_skill_code": "SA3",
"core_skill_desc": "follow guidelines/procedures/rules and service level agreements"
},{
"core_skill_code": "SA4",
"core_skill_desc": "ask for clarification and advice from others"
}
]};
var employee0 = {
"_id": "b013dcf12d1f7d333467b12350007op",
"_rev": "3-e54ad6a14046f809e6da156794939f12",
"employee_name" :"Ashwin",
"employee_role" : "Software engineer",
"core_skills":["SA1","SA4"]
};
Creating a skills index makes looking for particular skills much simpler, some code to do that is:
var skillCodeIndex = {};
skillCodes.core_skills.forEach(function(item){
skillCodeIndex[item.core_skill_code] = item.core_skill_desc;
});
Now all that is required is a function to get the skills for a particular employee, say:
function getCoreSkills (employee) {
console.log('Employee ' + employee.employee_name + ' has the following core skills:');
employee.core_skills.forEach(function(skill) {
console.log(skill + ': ' + skillCodeIndex[skill]);
});
}
An example:
getCoreSkills(employee0);
Employee Ashwin has the following core skills:
SA1: communicate with others in writing
SA4: ask for clarification and advice from others
The above could become much more OO given constructors for skillCodes and employee instances, I'll leave that to you.

Related

Mongo db update a nested array with many elements in a nested array

I have a db that looks like this :
{
"_id": "637c648fb8fcfb2bc3071bb9",
"consultant_name": "Sam smith",
"consultantUsername": "sam",
"consultant_Password": "123",
"type": "consultant",
"clients": [
{
"client_name": "john",
"client_Username": "mouh",
"client_Password": "123",
"type": "client",
"documents": [
{
"name": "Passeport",
"description": "copie conforme certifié de tout le passeport",
"doc_upload": "Capture dâeÌcran, le 2022-11-28 aÌ 23.01.12.png",
"_id": "637c648fb8fcfb2bc3071bbb"
},
{
"name": "Acte de naissance",
"description": "Pour prouver la filiation",
"doc_upload": "_Abstract Aesthetic CD Album Cover Art.png 637c648fb8fcfb2bc3071bbc",
"_id": "637c648fb8fcfb2bc3071bbc"
}
],
"_id": "637c648fb8fcfb2bc3071bba"
},
As you can see, Sam smith has different clients and each of those clients have different documents. My goal is to be able to allow Sam to add one more client to his portfolio AND specify the documents (as many as he wants) of that new user created all at once (when Sam creates a new user in the db). The process I used is to update his client list by creating an new client.
Here’s the code to add a client (that works), please note that the document part doesn’t get updated :
router.put("/:id", async(req,res)=>{
try {
const updateUser = await User.findByIdAndUpdate(req.params.id, {
$push: {
clients:{
client_name: req.body.client_name,
client_Username: req.body.client_Username,
client_Password: req.body.client_Password,
//documents not updating even with one single entry
documents : [
{
name : req.body.docName,
description : req.body.docDescription,
doc_upload : req.body.doc_upload,
}
]
}
}
},{new:true});
res.status(200).json(updateUser);
}
catch(err) {
res.status(500).json(err);
}
});
So my instinct here would be to push documents using the $each operator, but because the document update doesn't work I'm kind of stuck. In an ideal world if you have the answer/reflexion to be able to update the document part with multiple values it would be appreciated. Any idea on what to do or where should I look first ?

Is it possible to get a list of all items in an array of objects that match items in another array?

I'm working on a React project that'll allow me to search through a list of games to help me decide what to play based on what I'm in the mood for, currently I can add games to a JSON file but I'm really struggling with the searching part.
Right now, to add a new game, you'll enter the title, genre(s) and a description of the game. The genre field is a ReduxForm FieldArray object, and I think that's what's giving me the trouble. Here's my current JSON file
{
"games": [
{
"name": "Rainbow Six: Siege",
"genres": [
{
"genre": "tactical"
},
{
"genre": "shooter"
}
],
"description": "tactical team based shooter",
"id": 1
},
{
"name": "Resident Evil 2",
"genres": [
{
"genre": "horror"
},
{
"genre": "survival"
},
{
"genre": "shooter"
}
],
"description": "classic resident evil 2 remake in 2019",
"id": 2
},
{
"name": "Rocket League",
"genres": [
{
"genre": "cars"
},
{
"genre": "competition"
},
{
"genre": "one more game"
}
],
"description": "soccar!",
"id": 3
}
]
}
This is the dummy data I'm using to search:
const searchedGenres = 'horror, shooter';
const searchedList = searchedGenres.split(', ');
let foundGame = [];
Once I get the search working with this data, the plan is to allow me to just type in data on the frontend in one textbox, so "horror, shooter" would be my search term. The result from this search should only return Resident Evil 2, however I'm also receiving Rainbow Six: Siege as a result, even though it's missing one of my requested genres.
searchedList.forEach(searchedGenre => {
this.props.games.map(game => {
if (
game.genres.find(
({ genre }) =>
genre.toLowerCase() ===
searchedGenre.toLowerCase().trim()
) !== undefined
) {
foundGames.push(game);
}
});
});
I understand why I'm getting both Rainbow Six and Resident Evil as a result, because I'm not actually checking that both genres are in the games genres when I add the game to the foundGames array, but I'm completely lost on how I'd go about making sure all of the genres are in a game before I add it.
This would be a bit easier if your genres was a simple array of strings rather than objects, but still you can check pretty succinctly by leveraging some() and every() within filter() (btw filter() is a better choice than map() + push() here)
let games = [{"name": "Rainbow Six: Siege","genres": [{"genre": "tactical"},{"genre": "shooter"}],"description": "tactical team based shooter","id": 1},{"name": "Resident Evil 2","genres": [{"genre": "horror"},{"genre": "survival"},{"genre": "shooter"}],"description": "classic resident evil 2 remake in 2019","id": 2},{"name": "Rocket League","genres": [{"genre": "cars"},{"genre": "competition"},{"genre": "one more game"}],"description": "soccar!","id": 3}]
const searchedGenres = 'horror, shooter';
const searchedList = searchedGenres.split(', ');
let foundGame = games.filter(game => searchedList.every(searchItem => game.genres.some(g => g.genre == searchItem) ))
console.log(foundGame)
The filter condition basically says you want every game in searchedList to match at least one genre in the game. This will make it only return games that match every genre.

Creating Classroom using App Script

I'm trying to create Google classrooms from a spreadsheet using App Script. I can create the classes successfully, but it's not adding the course materials (1 Doc) to the about page.
This is the code I am using and I've tried using the API reference to no avail.
Can someone please advise me on how to correctly format the courseMaterialSets to include a Google Doc from my drive.
var create = Classroom.Courses.create({
"ownerId": '-My email address-',
"name": getData[i][0],
"section": getData[i][1],
"descriptionHeading": getData[i][2],
"description": getData[i][2],
"courseMaterialSets" : [{
"title" : 'Course Outline',
"materials" : [{
"driveFile" : {
"id" : getData[i][5],
"title" : 'Course Outline' ,
"alternateLink": getData[i][4],
"thumbnailUrl" : 'https://drive.google.com/uc?export=download&id=-Image ID-',
},
}
]
}
]
})
}
Logger.log(create)
}
Thank you.
EDIT
I've updated the code to reflect the suggestions in the comments and logged the value of var create which returns all of the info of the newly created Classroom but with no mention of the course material set.
According to the documentation you have to specify the DriveFile object with JSON.
"driveFile" : {
"id": theDocIdString,
"title": theDocTitleString,
"alternateLink": urlToFileString,
"thumbnailUrl": imgThumbnailString
}
You can of course pull all of this data from a sheet or use variables to loop through resources.
Here is the code I tried to successfully create a course, but I also do not get the course materials to attach to the ABOUT tab of the Google Classroom created.
function createCourse() {
var resource = {
name: "XYZ course",
room: "The Great Hall",
ownerId: "me",
courseMaterialSets: [{
title: "course materials",
materials: [
{
driveFile: {
id: "insert id of google drive file"
}
}
],
}],
}
var newCourse = Classroom.Courses.create(resource);
}
I also tried creating the course and then accepting the course in Google Classroom and the trying to add the classroom set. This also was not successful.
function addClassSet() {
var id = "course id obtained with sample script in documentation";
var resource = {
name: "XYZ course",
room: "The Great Hall",
courseMaterialSets: [{
title: "course materials",
materials: [
{
driveFile: {
id: "drive file id" //drive file was not added
}
}
],
}],
description: "This is a trial course", //this worked
}
Classroom.Courses.update(resource, id);
}
Is it because the documentation states that the courseMaterialsSets is Read only???

MongoDb: How to get a field (sub document) from a document?

Consider this example collection:
{
"_id:"0,
"firstname":"Tom",
"children" : {
"childA":{
"toys":{
'toy 1':'batman',
'toy 2':'car',
'toy 3':'train',
}
"movies": {
'movie 1': "Ironman"
'movie 2': "Deathwish"
}
},
"childB":{
"toys":{
'toy 1':'doll',
'toy 2':'bike',
'toy 3':'xbox',
}
"movies": {
'movie 1': "Frozen"
'movie 2': "Barbie"
}
}
}
}
Now I would like to retrieve ONLY the movies from a particular document.
I have tried something like this:
movies = users.find_one({'_id': 0}, {'_id': 0, 'children.ChildA.movies': 1})
However, I get the whole field structure from 'children' down to 'movies' and it's content. How do I just do a query and retrieve only the content of 'movies'?
To be specific I want to end up with this:
{
'movie 1': "Frozen"
'movie 2': "Barbie"
}
The problem here is your current data structure is not really great for querying. This is mostly because you are using "keys" to actually represent "data points", and while it might initially seem to be a logical idea it is actually a very bad practice.
So rather than do something like assign "childA" and "childB" as keys of an object or "sub-document", you are better off assigning these are "values" to a generic key name in a structure like this:
{
"_id:"0,
"firstname":"Tom",
"children" : [
{
"name": "childA",
"toys": [
"batman",
"car",
"train"
],
"movies": [
"Ironman"
"Deathwish"
]
},
{
"name": "childB",
"toys": [
"doll",
"bike",
"xbox",
],
"movies": [
"Frozen",
"Barbie"
]
}
]
}
Not the best as there are nested arrays, which can be a potential problem but there are workarounds to this as well ( but later ), but the main point here is this is a lot better than defining the data in "keys". And the main problem with "keys" that are not consistently named is that MongoDB does not generally allow any way to "wildcard" these names, so you are stuck with naming and "absolute path" in order to access elements as in:
children -> childA -> toys
children -> childB -> toys
And that in a nutshell is bad, and compared to this:
"children.toys"
From the sample prepared above, then I would say that is a whole lot better approach to organizing your data.
Even so, just getting back something such as a "unique list of movies" is out of scope for standard .find() type queries in MongoDB. This actually requires something more of "document manipulation" and is well supported in the aggregation framework for MongoDB. This has extensive capabilities for manipulation that is not present in the query methods, and as a per document response with the above structure then you can do this:
db.collection.aggregate([
# De-normalize the array content first
{ "$unwind": "$children" },
# De-normalize the content from the inner array as well
{ "$unwind": "$children.movies" },
# Group back, well optionally, but just the "movies" per document
{ "$group": {
"_id": "$_id",
"movies": { "$addToSet": "$children.movies" }
}}
])
So now the "list" response in the document only contains the "unique" movies, which corresponds more to what you are asking. Alternately you could just $push instead and make a "non-unique" list. But stupidly that is actually the same as this:
db.collection.find({},{ "_id": False, "children.movies": True })
As a "collection wide" concept, then you could simplify this a lot by simply using the .distinct() method. Which basically forms a list of "distinct" keys based on the input you provide. This playes with arrays really well:
db.collection.distinct("children.toys")
And that is essentially a collection wide analysis of all the "distinct" occurrences for each"toys" value in the collection, and returned as a simple "array".
But as for you existing structure, it deserves a solution to explain, but you really must understand that the explanation is horrible. The problem here is that the "native" and optimized methods available to general queries and aggregation methods are not available at all and the only option available is JavaScript based processing. Which even though a little better through "v8" engine integration, is still really a complete slouch when compared side by side with native code methods.
So from the "original" form that you have, ( JavaScript form, functions have to be so easy to translate") :
db.collection.mapReduce(
// Mapper
function() {
var id this._id;
children = this.children;
Object.keys(children).forEach(function(child) {
Object.keys(child).forEach(function(childKey) {
Object.keys(childKey).forEach(function(toy) {
emit(
id, { "toys": [children[childkey]["toys"][toy]] }
);
});
});
});
},
// Reducer
function(key,values) {
var output = { "toys": [] };
values.forEach(function(value) {
value.toys.forEach(function(toy) {
if ( ouput.toys.indexOf( toy ) == -1 )
output.toys.push( toy );
});
});
},
{
"out": { "inline": 1 }
}
)
So JavaScript evaluation is the "horrible" approach as this is much slower in execution, and you see the "traversing" code that needs to be implemented. Bad news for performance, so don't do it. Change the structure instead.
As a final part, you could model this differently to avoid the "nested array" concept. And understand that the only real problem with a "nested array" is that "updating" a nested element is really impossible without reading in the whole document and modifying it.
So $push and $pull methods work fine. But using a "positional" $ operator just does not work as the "outer" array index is always the "first" matched element. So if this really was a problem for you then you could do something like this, for example:
{
"_id:"0,
"firstname":"Tom",
"childtoys" : [
{
"name": "childA",
"toy": "batman"
}.
{
"name": "childA",
"toy": "car"
},
{
"name": "childA",
"toy": "train"
},
{
"name": "childB",
"toy": "doll"
},
{
"name": "childB",
"toy": "bike"
},
{
"name": "childB",
"toy": "xbox"
}
],
"childMovies": [
{
"name": "childA"
"movie": "Ironman"
},
{
"name": "childA",
"movie": "Deathwish"
},
{
"name": "childB",
"movie": "Frozen"
},
{
"name": "childB",
"movie": "Barbie"
}
]
}
That would be one way to avoid the problem with nested updates if you did indeed need to "update" items on a regular basis rather than just $push and $pull items to the "toys" and "movies" arrays.
But the overall message here is to design your data around the access patterns you actually use. MongoDB does generally not like things with a "strict path" in the terms of being able to query or otherwise flexibly issue updates.
Projections in MongoDB make use of '1' and '0' , not 'True'/'False'.
Moreover ensure that the fields are specified in the right cases(uppercase/lowercase)
The query should be as below:
db.users.findOne({'_id': 0}, {'_id': 0, 'children.childA.movies': 1})
Which will result in :
{
"children" : {
"childA" : {
"movies" : {
"movie 1" : "Ironman",
"movie 2" : "Deathwish"
}
}
}
}

Populate AngularJS {{expression}} within ng-repeat using a second array

I'm completely rebuilding my website (originally hacked together with Wordpress) using Laravel and AngularJS. It's been a massive learning experience and I think I'm nearly there but for one problem.
On my site 'schemes' (or courses) are made up of 'units' which are made up of 'lessons'. Retrieving this data is fine, using Eloquent I retrieve valid JSON like this made up example...
[
{
"id": "1", //Scheme Id
"title": "Sports",
"description": "This is a Sports course!",
"units": [
{
"id": "1",
"title": "Tennis",
"lessons": [
{
"id": "6",
"title": "Serving"
},
{
"id": "7",
"title": "Hitting the ball with top-spin"
}
]
},
{
"id": "2",
"title": "Athletics",
"lessons": [
{
"id": "1",
"title": "Long Jump"
},
{
"id": "2",
"title": "Hurdling Technique"
}
]
},
{
"id": "4",
"title": "Golf",
"lessons": [
{
"id": "4",
"title": "Pitching"
},
{
"id": "5",
"title": "Putting"
}
]
}
]
}
....
]
Separately I have a simple array of completed lesson ids for a particular user like this...
[2, 6, 8, 9] ///User has completed lessons with ids of 2,6,8 and 9
In my view I'm using nested ng-repeat loops like so...
...
<div ng-controller="SchemesController">
<div ng-repeat="scheme in schemes">
<h1>{{scheme.title}}</h1>
<div ng-repeat="unit in scheme.units">
<h3>{{unit.title}}</h3>
<div ng-repeat="lesson in unit.lessons">
<div>{{lesson.title}}: {{status}}</div>
</div>
</div>
</div>
</div><!--[end of ng-controller="SchemesController"]-->
....
SchemesController (v simple!) looks like this...
var app = angular.module('schemesApp', []);
app.controller('SchemesController', function($scope){
$scope.schemes=jsonData;
});
The problem is I have no idea how to populate the {{status}} field which I want to state simply 'Complete' or 'Incomplete. I investigated whether I could somehow add this info to my original array like this...
"lessons": [
{
"id": "6",
"title": "Serving",
"status": "Complete" //populated somehow
},
{
"id": "7",
"title": "Hitting the ball with top-spin",
}
]
but I got nowhere slowly. Is there a way to do this (I've played around with underscore.js and felt this could help?).
Or do I populate {{status}} from creating and calling a javascript function?!?
ANY help that anyone could offer would be incredible. I'm a school teacher and for some sadistic reason I find a bit of programming/web design a fun use of my spare time so I apologise if this is a stupid question. THANKS in advance!!!
btw if anyone has a better 'title' for this question then please let me know.
I'm assuming you don't need to persist the status back to the database...
This is where you're having the problem:
<div>{{lesson.title}}: {{status}}</div>
You really don't need to store the status in your data model, because it's just used for presentation purposes.
Let's say your array of completed lessons is defined like this:
$scope.completedLessons = [1, 2, 3, 4, 5] // Or however you'd assign it
You need to create a function in your scope like this:
$scope.isLessonCompleted = function(lessonId) {
return $scope.completedLessons.indexOf(lessonId) > -1;
};
Then you need to change the html from above to this:
<div>{{lesson.title}}: {{isLessonCompleted(lesson.id) && 'Complete' || 'Incomplete'}}</div>
If lessons are also a model and each lesson should have a status, which isn't a column/field in your table but is something you'll add logic to determine, you could add a custom model accessor by adding the following to your models/Lesson.php:
// Append custom accessor attributes
protected $appends = ['status'];
public function getStatusAttribute() {
// Add logic here
return 'Complete';
}
This way, when you use Eloquent to retrieve your data, you'll also see a status attribute as part of the object, so you could then access it as usual $lesson->status (PHP) or lesson.status (JS).
For more information, see the official Laravel documentation on accessors and mutators

Categories

Resources