I have a Mongo collection that looks similar to the below example, I am using meteor-publish-composite, https://atmospherejs.com/reywood/publish-composite to publish documents to the client. I know with Mongo I can do the following to return specific items within the authors array.
db.books.find({"authors.authorSlug": "author-1}, {authors: {$elemMatch: { authorSlug: "author-1"}});
When I try to achieve the same thing using meteor-publish-composite, this does not seem to work as it returns the entire the authors' array, my code is as below.
Books.find({"authors.authorSlug": slug}, {authors: {$elemMatch:{authorSlug: slug}}});
Is this even possible to achieve with publish-composite?
{
"title" : "Book1",
"authors" : [
{
"name" : "Author 1",
"authorSlug": "author-1"
},
{
"name" : "Author 2",
"slug" : "author-2"
},
],
"slug" : "book1"
}
You only use publish-composite when you are trying to join 2 or more related collections into a single reactive subscription. You simply need a standard publish/subscribe for your collection - and you say you have working code so I don't see what your problem is! Or are you trying to get at your books data in addition to other data around it?
Related
I'm new to VTL and AWS appsync and try to get my head around how things are working.
The maps that are representing Steps in a List should have the property id with a UUID before there are stored in DynamoDB. To accomplish this I tried to iterate over the array and access the put method on the map like in the example below.
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key": {
"id" : $util.dynamodb.toDynamoDBJson($util.autoId())
},
#set($input = $util.dynamodb.toMapValues($ctx.args.input))
#set($input.createdAt = $util.dynamodb.toDynamoDB($util.time.nowISO8601()))
#foreach($step in $input.steps)
$step.put('id', $util.dynamodb.toDynamoDBJson($util.autoId())))
#end
"attributeValues": $util.toJson($input)
}
my second try:
#foreach($step in $input.steps)
#set($step.id = $util.dynamodb.toDynamoDBJson($util.autoId()))
#end
but still, for no reason, my maps do not have the property id.
Is there maybe the problem what the foreach loop is giving me just a copy of the map I try to modify and not the original object?
Thank you for your time!
Hopefully, my question will serve all newbies to VTL and appsync
They do, it's just that the toMapValues utility method is returning you DynamoDB types.
So if "input.steps" is supposed to be a list what you're gonna get in there is an object like {"L": [ ... ]}
Try this:
#foreach($step in $input.steps.L)
$step.put('id', $util.dynamodb.toDynamoDBJson($util.autoId())))
#end
How can I get a collection where the query should be applicable to an array inside the document.
Document example: I would like to know how to query the document where the brands are fiat and seat
{
"name":"test 1",
"brands":[
{
"brand":{
"id":1,
"name":"Fiat",
"slug":"fiat",
"image":null,
"year_end":null,
"year_start":null
},
"released_at":"2018-10-26"
},
{
"brand":{
"id":2,
"name":"Seat",
"slug":"seat",
"image":null,
"year_end":null,
"year_start":null
},
"released_at":"2018-10-26"
},
{
"brand":{
"id":3,
"name":"Mercedes",
"slug":"mercedes",
"image":null,
"year_end":null,
"year_start":null
},
"released_at":"2018-10-26"
},
{
"brand":{
"id":4,
"name":"Yamaha",
"slug":"yamaha",
"image":null,
"year_end":null,
"year_start":null
},
"released_at":"2018-10-26"
}
]
}
I have tried something like:
.collection("motors")
.where("brands.slug", "array-contains-any", ["fiat", "seat"])
but this is not working I cannot figure out by the documentation how to get this.
When using the array-contains-any operator, you can check the values of your array against the value of a property of type String and not an array. There is currently no way you can use array-contains-any operator on an array. There are two options, one would be to create two separate fields and create two separate queries or, been only a document, you can get the entire document and filter the data on the client.
Edit:
What #FrankvanPuffelen has commented is correct, I made some research and I found that we can check against any type and even complex types, not just against strings, as mentioned before. The key to solving this issue is to match the entire object, meaning all properties of that object and not just a partial match, for example, one of three properties.
What you are trying to achieve is not working with your current database structure because your slug property exists in an object that is nested within the actual object that exists in your array. A possible solution might also be to duplicate some data and add only the desired values into an array and use the array-contains-any operator on this new creatded array.
I'm making an app with database structure like this:
{
"Locations": {
"location1": {
"name": "Nice location"
}
},
"User_posts": {
"user1": {
"post1": {
"location_name": "Nice location",
"location_id": "location1",
"description": "Wow!"
},
"post2": {
"location_name": "Nice location",
"location_id": "location1",
"description": "Nice"
}
}
}
If I have to change location1 name, how to change all location_name's that all users posts have? I have to download all the data before and update it or there is other method?
I think that using location id only to get location name for every location when user enters his posts is not a good idea.
By duplicating data you improve your read performance/scalability at the cost of decreased write performance. This is a normal trade-off in NoSQL databases and in highly scaleable systems in general.
If you want to update the location_name of all posts, you will indeed have to query the posts and update each. If you need to do this regularly, consider keeping a separate lookup list for each location to find the posts where it used. Such an inverted index is another common occurrence in NoSQL databases.
I covered strategies for updating the duplicated data in my answer here: How to write denormalized data in Firebase
Coming from a relational/SQL background, this may initially feel uncomfortable, since it goes against the normalization rules we've been taught. To counter that feeling, I recommend reading NoSQL data modeling, watching Firebase for SQL developers and in general just read some more NoSQL data modeling questions.
You can add one more attribute to location1 , say isLocationOf , which will store all the user id or perhaps post id/post names. Like
"Locations": {
"location1": {
"name": "Nice location",
"isLocationOf": {
'post1': true,
'post2': true
}
}
}
Here isLocationOf is an attribute of Locations whose value is an object.Now if locations1's name gets changed then you can retrieve its isLocationOf object , iterate through it , get all posts id/name containing that location.Then use the post ids to update all entries having this address .
Also whenever you add new post , you have to add its post id/name to isLocation object.
The current query you see below is not efficient because I have not setup the proper indexing. I get the suggestion Consider adding ".indexOn": "users/kxSWLGDxpYgNQNFd3Q5WdoC9XFk2" at /conversations in the console in Xcode. I have tried it an it works.
However, I need the user id after users/ to be dynamic. I've added a link to another post below that has tried a similar thing, but I just can't seem to get it. All help would be much appreciated!
Note: The console output user id above does not match the screenshot below, but does not matter to solve the problem I believe. Correct me if I'm wrong. Thanks!
Here is the structure of my DB in Firebase:
{
"conversationsMessagesID" : "-KS3Y9dMLXfs3FE4nlm7",
"date" : "2016-10-19 15:45:32 PDT",
"dateAsDouble" : 4.6601793282986E8,
"displayNames" : [ “Tester 1”, “Tester 2” ],
"hideForUsers" : [ "SjZLsTGckoc7ZsyGV3mmwc022J93" ],
"readByUsers" : [ "mcOK5wVZoZYlFZZICXWYr3H81az2", "SjZLsTGckoc7ZsyGV3mmwc022J93" ],
"users" : {
"SjZLsTGckoc7ZsyGV3mmwc022J93" : true,
"mcOK5wVZoZYlFZZICXWYr3H81az2" : true
}
}
and the Swift query:
FIRDatabase.database().reference().child("conversations")
.queryOrderedByChild("users/\(AppState.sharedInstance.uid!)").queryEqualToValue(true)
Links to other post:
How to write .indexOn for dynamic keys in firebase?
It seems fairly simple to add the requested index:
{
"rules": {
"users": {
".indexOn": ["kxSWLGDxpYgNQNFd3Q5WdoC9XFk2", "SjZLsTGckoc7ZsyGV3mmwc022J93", "mcOK5wVZoZYlFZZICXWYr3H81az2"]
}
}
}
More likely your concern is that it's not feasible to add these indexes manually, since you're generating the user IDs in your code.
Unfortunately there is no API to generate indexes.
Instead you'll need to model your data differently to allow the query that you want to do. In this case, you want to retrieve the conversations for a specific user. So you'll need to store the conversations for each specific user:
conversationsByUser {
"SjZLsTGckoc7ZsyGV3mmwc022J93": {
"-KS3Y9dMLXfs3FE4nlm7": true
},
"mcOK5wVZoZYlFZZICXWYr3H81az2": {
"-KS3Y9dMLXfs3FE4nlm7": true
}
}
It may at first seem inefficient to store this data multiple times, but it is very common when using NoSQL databases. And is really no different than if the database would auto-generate the indexes for you, except that you have to write the code to update the indexes yourself.
I need to get the PHIDs for one project and several users in our Phabricator install. It seems like it should be trivial to find out how to do this, but I've searched the docs to no avail. Am I looking in the wrong place or something?
Easiest way:
Go to the project
Click New Task
Look at the URL, it will have a parameter like:
?projects=PHID-PROJ-owipizovyry4fatifwfd
PHID is "PHID-PROJ-owipizovyry4fatifwfd"
Option 2:
Go to your Conduit [phabricator_url]\conduit
Find the method project.query
Enter the name in a JSON encoded array (i.e. ["project name"])
Click Call Method
PHID will be one of the data elements:
{
"data" : {
"PHID-PROJ-oybqquyhhke4awiw2akz" : {
"id" : "19",
"phid" : "PHID-PROJ-oybqquyhhke4awiw2akz",
"name" : "project name",
"members" : [
"PHID-USER-gapak5h34h6d5yvl67dx",
"PHID-USER-674vq754zfuhyxgvvq7x",
"PHID-USER-qvcdsyc4oz7rzpzziiyk",
"PHID-USER-qmefzjtsrmnxjxpc45km",
"PHID-USER-pbhygge7rgpdowz3s5vk"
],
"slugs" : [
"project_name"
],
"dateCreated" : "1396666703",
"dateModified" : "1396668261"
}
}
}
A more robust method would be to call the conduit method phid.lookup:
https://<your install>/conduit/method/phid.lookup/
Then enter in names something like #user, #project or Z2 and you'll get the PHID.