Waterline: Find by value in JSON - javascript

I have a nested address attribute in one of my models.
attributes: {
address: {
type: 'json'
}
}
How can I find model instances located i.e. the same city.
I tried several queries:
Model.find({ "address.city": city })
Model.find({ address: { contains: city }})
But none seem to work for. Any ideas on how to properly formulate this query?

For sure, a mongo native call powered by Warerline works: https://sailsjs.com/documentation/reference/waterline-orm/models/native
Then the query object in your first attempt should work. Beware that then the mongodb documentation is the leading over the waterline one regarding query parameters. E.g. you need to cast ObjectId on id queries before using them in a native query.

Related

Query stored values that contain specific string

I have a small realtime firebase database that's set up like this:
database
-messages
--XXXXXXXXXXXX
---id : "XXX-XXX"
---content : "Hello world!"
It's a very simple message system, the id field is basically a combination of users id from my mysql database. I'm trying to return all messages that match one of the ids, either sender or receiver. But I can't do it, seems like firebase only support exacts querys. Could you give me some guidanse?
Here's the code I'm working with
firebase.database().ref("messages").orderByChild("id").equalTo(userId).on("value", function(snapshot)
I'm looking for something like ".contains(userId)"
Firebase supports exact matches (with equalTo) and so-called prefix queries where the value starts with a certain value (by combining startAt and endAt). It does not support querying for values that end with a certain value.
I recommend keeping a mapping from each user IDs to their messages nodes, somewhere separately in their database.
So say that you have:
messages: {
"XXXXXXXXXXXX": {
id : "YYY-ZZZ",
content : "Hello world!"
}
}
You also have the following mappings:
userMessages: {
"YYY": {
"XXXXXXXXXXXX": true
},
"ZZZ": {
"XXXXXXXXXXXX": true
}
}
Now with this information you can look up the messages for each user based on their ID.
For more on the modeling of this type of data, I recommend:
Best way to manage Chat channels in Firebase
Many to Many relationship in Firebase
this artcle on NoSQL data modeling

Apollo Client - using cached results from object list in response to query for single object

Is it possible to configure the Apollo Client to fetch a single cached Item from a query that returns a list of Items, in order to prefetch data when querying for a single Item?
Schema:
type Item {
id: ID!
name: String!
}
type Query {
items: [Item!]!
itemById(id: ID!): Item!
}
Query1:
query HomepageList {
items {
id
name
}
}
Query2:
query ItemDetail($id: ID!) {
itemById(id: $id) {
id
name
}
}
Given that the individual Item's data will already be in the cache, it should be possible to use the already cached data whilst still executing a fetch incase any data has changed.
However, the query does not utilise the cached data (by default at least), and it seems that we need to somehow tell Apollo that we know the Item is already in the cache.
Any help greatly appreciated.
This functionality exists, but it's hard to find if you don't know what you're looking for. In Apollo Client v2 you're looking for cache redirect functionality, in Apollo Client v3 this is replaced by type policies / field read policies (v3 docs).
Apollo doesn't 'know' your GraphQL schema and that makes it easy to set up and work with in day-to-day usage. However, this implies that given some query (e.g. getBooks) it doesn't know what the result type is going to be upfront. It does know it afterwards, as long as the __typename's are enabled. This is the default behaviour and is needed for normalized caching.
Let's assume you have a getBooks query that fetches a list of Books. If you inspect the cache after this request is finished using Apollo devtools, you should find the books in the cache using the Book:123 key in which Book is the typename and 123 is the id. If it exists (and is queried!) the id field is used as identifier for the cache. If your id field has another name, you can use the typePolicies of the cache to inform Apollo InMemoryCache about this field.
If you've set this up and you run a getBook query afterwards, using some id as input, you will not get any cached data. The reason is as described before: Apollo doesn't know upfront which type this query is going to return.
So in Apollo v2 you would use a cacheRedirect to 'redirect' Apollo to the right cache:
cacheRedirects: {
Query: {
getBook(_, args, { getCacheKey }) {
return getCacheKey({
__typename: 'Book',
id: args.id,
});
}
},
},
(args.id should be replaced by another identifier if you have specified another key in the typePolicy)
When using Apollo v3, you need a typepolicy / field read policy:
typePolicies: {
Query: {
fields: {
getBook(_, { args, toReference }) {
return toReference({
__typename: 'Book',
id: args.id,
});
}
}
}
}

Firebase database: how to get first record of each list

I have a nested firebase database with a structure like this:
posts: {
0: {
title: "...",
content: '...',
comments: [{
by: "someone"
}, {
by: "anotherone"
}]
},
1: {
...
}
}
Now I want to get the first comments on each post so I tried
firebase.database().ref('/posts/{postId}/comments/0').once('value',function(snapshot){
snapshot.forEach(function(child){ console.log(child.val());});
})
But don't know why the only thing I got in the console is false. So are there anyone knows what's wrong or is it impossible to query like that?
The Firebase Database SDKs will also read entire nodes. It is not possible to retrieve a subset of a node's data or to get just the keys.
To get the first comment of each post, you must know the key of each post already. Since you can't read just the keys of the posts, this means that you must read all data to get just the first comment of each post:
firebase.database().ref('/posts').once('value',function(snapshot){
snapshot.forEach(function(child){
console.log(child.val().comments[0]);
});
})
While this gives the result you need, it is quite wasteful in bandwidth: the client is ready way more data than you need. As usual in NoSQL databases, a better solution may require you to change your data model to fit your use-case. For example: consider storing the latest comment for each post in a separate top-level list:
latest-comments: {
0: {
by: "someone"
},
1: {
...
}
}
You will need to update this list (in addition to your original comments list) whenever a new comment is posted. But in return, reading the latest comment for each post is now very cheap.

Write an object containing an array of objects to a mongo database in Meteor

In my user collection, I have an object that contains an array of contacts.
The object definition is below.
How can this entire object, with the full array of contacts, be written to the user database in Meteor from the server, ideally in a single command?
I have spent considerable time reading the mongo docs and meteor docs, but can't get this to work.
I have also tried a large number of different commands and approaches using both the whole object and iterating through the component parts to try to achieve this, unsuccessfully. Here is an (unsuccessful) example that attempts to write the entire contacts object using $set:
Meteor.users.update({ _id: this.userId }, {$set: { 'Contacts': contacts}});
Thank you.
Object definition (this is a field within the user collection):
"Contacts" : {
"contactInfo" : [
{
"phoneMobile" : "1234567890",
"lastName" : "Johnny"
"firstName" : "Appleseed"
}
]
}
This update should absolutely work. What I suspect is happening is that you're not publishing the Contacts data back to the client because Meteor doesn't publish every key in the current user document automatically. So your update is working and saving data to mongo but you're not seeing it back on the client. You can check this by doing meteor mongo on the command line then inspecting the user document in question.
Try:
server:
Meteor.publish('me',function(){
if (this.userId) return Meteor.users.find(this.userId, { fields: { profile: 1, Contacts: 1 }});
this.ready();
});
client:
Meteor.subscribe('me');
The command above is correct. The issue is schema verification. Simple Schema was defeating the ability to write to the database while running 'in the background'. It doesn't produce an error, it just fails to produce the expected outcome.

Sails.js Waterline query by association

I'm developing and app with Sails.js and using Waterline orm for db. I'm developing functionality for users to do friend requests and other similar requests to each other. I have following URequest model for that:
module.exports = {
attributes: {
owner: {
model: 'Person'
},
people: {
collection: 'Person'
},
answers: {
collection: 'URequestAnswer'
},
action: {
type: 'json' //TODO: Consider alternative more schema consistent approach.
}
}
};
Basically owner is association to Person who made the request and people is one-to-many association to all Persons who the request is directed. So far fine.
Now I want to have a controller which returns all requests where certain user is involved in meaning all requests where user is either in owner field or in people. How I do query like "give me all rows where there is association to person P" ? In other words how I ca know which URequest models have association to a certain Person?
I tried something like this:
getRequests: function (req, res) {
var personId = req.param('personId');
URequest.find().where({
or: [
{people: [personId]}, //TODO: This is not correct
{owner: personId}
]
}).populateAll().then(function(results) {
res.json(results);
});
},
So I know how to do the "or" part but how do I check if the personId is in people? I know I should somehow be able to look into join-table but I have no idea how and couldn't find much from Waterline docs relating to my situation. Also, I'm trying to keep this db-agnostic, though atm I'm using MongoDB but might use Postgres later.
I have to be honest this is a tricky one, and, as far as I know what you are trying to do is not possible using Waterline so your options are to write a native query using query( ) if you are using a sql based adapter or native otherwise, or try doing some manual filtering. Manual filtering would depend on how large of a dataset you are dealing with.
My mind immediately goes to reworking your data model a bit, maybe instead of a collection you have a table that stores associations. Something like this:
module.exports = {
attributes: {
owner: {
model: 'URequest'
},
person: {
model: 'Person'
}
}
Using the sailsjs model methods (like beforeCreate) you could auto create these associations as needed.
Good Luck, I hope you get it working!

Categories