Mapping through multiple arrays of objects and comparing ids - reactjs

So I have a bit of a dilemma. I am creating a forum and I am calling 3 different API's. Suppose I have multiple JSONs:
let forumPost= [{
"userId": 1,
"postId": 1,
"postTitle": "I am the post title",
"postBody": "I am the post body"
}]
let forumUser= [{
"userId": 1,
"name": "Someone Someone",
"username": "Som",
}]
let forumComment = [{
"postId": 7,
"userId" : 10,
"body": "I don't like your post",
}]
I would now like to create something like this:
Post title
Post body
By user
-------------
CommentUser: CommentBody
CommentUser: CommentBody
In order to do this I am currently sort of doing nest mapping 3 times 3 different arrays of objects and comparing id's so:
forumPost.map(...
forumUser.map(...
forumComment.filter(...
(post.userId === user.userId){
<div>...</div>
}
I was wondering if there is a more efficient way of mapping and comparing multiple nested objects in vanilla ReactJS?

Related

How can I select a field and nested array from a JSON using JSONPath?

From the contacts, I'd like to select the values in fields: "Id" (47) and everything from the nested array [doNotContact]. I could use some help defining the JSONPath-filter I should be using to select the values: 47 and each value inside the nested array.
{
"total": "1",
"contacts": {
"47": {
"id": 47,
"isPublished": true,
"dateAdded": "2015-07-21T12:27:12-05:00",
"createdBy": 1,
"createdByUser": "Joe Smith",
"doNotContact": [{
"id": 2,
"reason": 2,
"comments": "",
"channel": "email",
"channelId": null
}]
}
}
}
I have tried paths like: $.contacts.*.['id','doNotContact'] however, this does not seem to work. I am using the website: https://goessner.net/articles/JsonPath/ normally this would help me solve the problem.
Not all implementations support the comma-delimited selectors, e.g. ['id','doNotContact']. See the JSON Path comparison project site (specifically this test) for information as to which implementations support the syntax.
Secondly, please see this answer about omitting the dot before a bracket syntax

MongoDB Array Query - Single out an array element

I am having trouble with querying a MongoDB collection with an array inside.
Here is the structure of my collection that I am querying. This is one record:
{
"_id": "abc123def4567890",
"profile_id": "abc123def4567890",
"image_count": 2,
"images": [
{
"image_id": "ABC123456789",
"image_url": "images/something.jpg",
"geo_loc": "-0.1234,11.234567890",
"title": "A Title",
"shot_time": "01:23:33",
"shot_date": "11/22/2222",
"shot_type": "scenery",
"conditions": "cloudy",
"iso": 16,
"f": 2.4,
"ss": "1/545",
"focal": 6.0,
"equipment": "",
"instructions": "",
"upload_date": 1234567890,
"update_date": 1234567890
},
{
"image_id": "ABC123456789",
"image_url": "images/something.jpg",
"geo_loc": "-0.1234,11.234567890",
"title": "A Title",
"shot_time": "01:23:33",
"shot_date": "11/22/2222",
"shot_type": "portrait",
"conditions": "cloudy",
"iso": "16",
"f": "2.4",
"ss": "1/545",
"focal": "6.0",
"equipment": "",
"instructions": "",
"upload_date": 1234567890,
"update_date": 1234567890
}
]
}
Forgive the formatting, I didn't know how else to show this.
As you can see, it's a profile with a series of images within an array called 'images' and there are 2 images. Each of the 'images' array items contain an object of attributes for the image (url, title, type, etc).
All I want to do is to return the object element whose attributes match certain criteria:
Select object from images which has shot_type = "scenery"
I tried to make it as simple as possible so i started with:
find( { "images.shot_type": "scenery" } )
This returns the entire record and both the images within. So I tried projection but I could not isolate the single object within the array (in this case object at position 0) and return it.
I think the answer lies with projection but I am unsure.
I have gone through the MongoDB documents for hours now and can't find inspiration. I have read about $elemMatch, $, and the other array operators, nothing seems to allow you to single out an array item based on data within. I have been through this page too https://docs.mongodb.com/manual/tutorial/query-arrays/ Still can't work it out.
Can anyone provide help?
Have I made an error by using '$push' to populate my images field (making it an array) instead of using '$set' which would have made it into an embedded document? Would this have made a difference?
Using aggregation:
db.collection.aggregate({
$project: {
_id: 0,
"result": {
$filter: {
input: "$images",
as: "img",
cond: {
$eq: [
"$$img.shot_type",
"scenery"
]
}
}
}
}
})
Playground
You can use $elemMatch in this way (simplified query):
db.collection.find({
"profile_id": "1",
},
{
"images": {
"$elemMatch": {
"shot_type": 1
}
}
})
You can use two objects into find query. The first will filter all document and will only get those whose profile_id is 1. You can omit this stage and use only { } if you wnat to search into the entire collection.
Then, the other object uses $elemMatch to get only the element whose shot_type is 1.
Check an example here

Query an array of users based on an array of users

Basically I'm having trouble understanding how I would figure this out.
I have a document in a mongodb collection, and that document has field called friends which is an array of usernames.
I want to query through each username in the array friends, and have an array of those user documents. I'm terrible at explaining maybe if I draw this out it'll make sense.
mongodb document:
{
"_id": {
"$oid": "59a20e65f94cb5e924af774e"
},
"name": "Nick",
"friends": ["Jones","Mark","Mike"]
}
Now with this friends array, I want to search the same collection for an object with the "name" Jones, Mark, and Mike. When I find that object, I want to put it into an array.
Basically I want it to return this, (for this example let's say Jones, Mark, and Mike only have one friend, and that friend is Nick.
[{
"_id": {
"$oid": "59a20e65f94cb5e924af774e"
},
"name": "Jones",
"friends": ["Nick"]
},
{
"_id": {
"$oid": "59a20e65f94cb5e924af774e"
},
"name": "Mark",
"friends": ["Nick"]
},
{
"_id": {
"$oid": "59a20e65f94cb5e924af774e"
},
"name": "Mike",
"friends": ["Nick"]
}]
^ an array of three objects, which are all the friends of Nick.
If you need any more explanation please let me know, I'm terrible at this type of stuff.
For the record, I'm using node, and basic mongodb (not mongoose).
I believe you are looking for $in operator.
// doc.friends = ["Jones","Mark","Mike"]
db.collection.find({ name: { $in: doc.friends }})

Multiple grids from the same store

I need to display product-wise sales data on grid panels on ExtJs3.2 - one grid per product.
The data is received year-wise,and is loaded into a jsonstore.
{"list": [
{
"Year": "2014",
"product": "IS",
"total": "5.0",
},
{
"Year": "2013",
"product": "IS",
"total": "5.6",
},
{
"Year": "2014",
"product": "NS",
"total": "5.7",
},
{
"Year": "2013",
"product": "NS",
"total": "5.1",
}
....
......
]
}
The response is processed to convert into a product-specific 'keyed' dictionary.
{ "IS":[{"Year":"2013","total":"5.1"},{"Year":"2013","total":"5.1"}..],
"NS":[{"Year":"2013","total":"5.1"},{"Year":"2013","total":"5.1"}..],
..}
Each key(and values) are then loaded into separate array stores to feed the respective grids.
Though simplistic - too many objects/structures are being created to achieve this.
Is there a more elegant way to load multiple grids from extracts of the store data?
If you have important reasons not to switch to MVC ExtJS 4 or MVVC ExtJS 5 you could provide data the needed way on server side. E.g. by Node.js what is fetching the JSON and reworking this. Your request could be more specific and your client App would become faster.
An other way would be to write convert() functions into your Ext.data fields and use them as source for the grid.

MongoDB Array Query Performance

I'm trying to figure out what the best schema is for a dating site like app. User's have a listing (possibly many) and they can view other user listings to 'like' and 'dislike' them.
Currently i'm just storing the other persons listing id in a likedBy and dislikedBy array. When a user 'likes' a listing, it puts their listing id into the 'liked' listings arrays. However I would now like to track the timestamp that a user likes a listing. This would be used for a user's 'history list' or for data analysis.
I would need to do two separate queries:
find all active listings that this user has not liked or disliked before
and for a user's history of 'liked'/'disliked' choices
find all the listings user X has liked in chronological order
My current schema is:
listings
_id: 'sdf3f'
likedBy: ['12ac', 'as3vd', 'sadf3']
dislikedBy: ['asdf', 'sdsdf', 'asdfas']
active: bool
Could I do something like this?
listings
_id: 'sdf3f'
likedBy: [{'12ac', date: Date}, {'ds3d', date: Date}]
dislikedBy: [{'s12ac', date: Date}, {'6fs3d', date: Date}]
active: bool
I was also thinking of making a new collection for choices.
choices
Id
userId // id of current user making the choice
userlistId // listing of the user making the choice
listingChoseId // the listing they chose yes/no
type
date
I'm not sure of the performance implications of having these choices in another collection when doing the find all active listings that this user has not liked or disliked before.
Any insight would be greatly appreciated!
Well you obviously thought it was a good idea to have these embedded in the "listings" documents so your additional usage patterns to the cases presented here worked properly. With that in mind there is no reason to throw that away.
To clarify though, the structure you seem to want is something like this:
{
"_id": "sdf3f",
"likedBy": [
{ "userId": "12ac", "date": ISODate("2014-04-09T07:30:47.091Z") },
{ "userId": "as3vd", "date": ISODate("2014-04-09T07:30:47.091Z") },
{ "userId": "sadf3", "date": ISODate("2014-04-09T07:30:47.091Z") }
],
"dislikedBy": [
{ "userId": "asdf", "date": ISODate("2014-04-09T07:30:47.091Z") },
{ "userId": "sdsdf", "date": ISODate("2014-04-09T07:30:47.091Z") },
{ "userId": "asdfas", "date": ISODate("2014-04-09T07:30:47.091Z") }
],
"active": true
}
Which is all well and fine except that there is one catch. Because you have this content in two array fields you would not be able to create an index over both of those fields. That is a restriction where only one array type of field (or multikey) can be be included within a compound index.
So to solve the obvious problem with your first query not being able to use an index, you would structure like this instead:
{
"_id": "sdf3f",
"votes": [
{
"userId": "12ac",
"type": "like",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "as3vd",
"type": "like",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "sadf3",
"type": "like",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "asdf",
"type": "dislike",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "sdsdf",
"type": "dislike",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "asdfas",
"type": "dislike",
"date": ISODate("2014-04-09T07:30:47.091Z")
}
],
"active": true
}
This allows an index that covers this form:
db.post.ensureIndex({
"active": 1,
"votes.userId": 1,
"votes.date": 1,
"votes.type": 1
})
Actually you will probably want a few indexes to suit your usage patterns, but the point is now can have indexes you can use.
Covering the first case you have this form of query:
db.post.find({ "active": true, "votes.userId": { "$ne": "12ac" } })
That makes sense considering that you clearly are not going to have both an like and dislike option for each user. By the order of that index, at least active can be used to filter because your negating condition needs to scan everything else. No way around that with any structure.
For the other case you probably want the userId to be in an index before the date and as the first element. Then your query is quite simple:
db.post.find({ "votes.userId": "12ac" })
.sort({ "votes.userId": 1, "votes.date": 1 })
But you may be wondering that you suddenly lost something in that getting the count of "likes" and "dislikes" was as easy as testing the size of the array before, but now it's a little different. Not a problem that cannot be solved using aggregate:
db.post.aggregate([
{ "$unwind": "$votes" },
{ "$group": {
"_id": {
"_id": "$_id",
"active": "$active"
},
"likes": { "$sum": { "$cond": [
{ "$eq": [ "$votes.type", "like" ] },
1,
0
]}},
"dislikes": { "$sum": { "$cond": [
{ "$eq": [ "$votes.type", "dislike" ] },
1,
0
]}}
])
So whatever your actual usage form you can store any important parts of the document to keep in the grouping _id and then evaluate the count of "likes" and "dislikes" in an easy manner.
You may also not that changing an entry from like to dislike can also be done in a single atomic update.
There is much more you can do, but I would prefer this structure for the reasons as given.

Resources