I'm using "dataFilter" with alloy.collection
function filterFunction(collection) {
var lang = parseInt(Alloy.Globals.Language);
return collection.where({
LangID : lang,
CategoryID : categoryId
});
}
and it works fine, my question is how can I use this approach with 'or' or 'and', I need to do something like ' where categoryId="1" or categoryId="2" or categoryId="3"'
I used query in fetching and it works fine too, but I want to know if it's possible to do it with dataFilter function.
Thanks.
underscore is installed by default with Alloy I believe so this should work
_.filter(Alloy.Globals.Language, function(i) {
return i.categoryId==="1" || i.categoryId==="2" || i.categoryId==="3"
});
Related
I am using YDN-DB for my web POS, library using clone from following source:
https://raw.githubusercontent.com/yathit/ydn-db/master/jsc/ydn.db-dev.js
All is going well, incorporation with indexed db.
The only concern is, i want to use LIKE for my query as shows below, but it does not work and return sql parsing error, it looks LIKE does not work in YDN-DB, can you please advise any solution to achieve this?
APP.db.executeSql("SELECT * FROM products WHERE name LIKE '%test%' ").then(function(results) {
console.log(results);
});
However following works good.
APP.db.executeSql("SELECT * FROM products WHERE name = 'test'").then(function(results) {
console.log(results);
});
i have tried the other way aswell, but available operator only supports the start of string search, as shows below:
var q = APP.db.from( 'products' ).where('name', '^', 'New');
var limit = 10000;
var result = [];
q.list( limit ).done( function( objs ) {
result = objs;
console.log(result);
});
Can any of you please help me out to achieve the nieche.
I am beginner in programming and interested to learn MeteorJS. I want to search category_name and subcategory_name by keyword or alphabet.:)
This is my code.
collections: subcategory
{
_id:"ZbwCsJEMi2DesyJA7",
category_name: "ICT",
subcategory_name: "Laptop"
}
subcategory.js
Template.Subcategory.events({
"keyup .searchbox": function(event){
var query = event.target.value;
Session.set('query', query);
}
});
Template.Subcategory.helpers({
subcategory: function(){
var filter = {sort: {}};
var query = Session.get('query');
filter.sort[Session.get('sortby')] = 1;
return Subcategory.find({ subcategory_name: new RegExp(query, 'i')} , filter );
}
});
Seems like you are looking for $or operator:
var queryRegexp = new RegExp(query, 'i');
return Subcategory.find({
$or: [
{ category_name: queryRegexp },
{ subcategory_name: queryRegexp }
]
} , filter);
Official Mongo's documentation for $or: https://docs.mongodb.org/manual/reference/operator/query/or/
You'll have to create a text index in Mongo. You can do this in Meteor still I think with something like this:
MyCollection._ensureIndex({
"$**": "text"
});
The above uses a wildcard but you can be more specific. See https://docs.mongodb.org/v3.0/core/index-text/ for more info.
For larger collections I tend to pass a text search query through a subscriptions so it can be performed on the server.
Assuming you want to show a list of things and allow users to filter them with the search box, you could do something like this:
Meteor.publish('MyCollection', function (searchTerm) {
return searchTerm ? MyCollection.find() : MyCollection.find({ $text: {$search: searchTerm} });
});
On the client, assuming you're using template-level subscriptions, you could set up your subscription like this:
Template.Subcategory.onCreated(function(){
var self = this;
// requires the reactive-var package
self.searchTerm = new ReactiveVar(false);
self.autorun(function(){
self.subscribe( "MyCollection", self.searchTerm.get() );
});
});
It'd then just be a case of setting your search term:
Template.Subcategory.events({
'keyup .searchbox': function(e,t){
var inputValue = e.currentTarget.value,
//you could set an arbitrary minimum search term length like so
searchTerm = inputValue.length > 1 ? inputValue : false;
t.searchTerm.set(searchTerm);
}
});
There's a couple of caveats on relying on the subscriptions so heavily like this. For example, if your collections are scoped globally on the client you run the risk of multiple subscriptions to the same collection giving you results you might not want to render within your list. Nevertheless, I quite like this approach. Food for thought.
I have a list of company names I'm populating from a collection
the helper function I have is:
Template.companyList.helpers({
companies: function () {
return Companies.find({owner: Meteor.userId()}, {sort: {a: 1}, name:1, createdAt:1});
}
});
It's looped through using a
{{#each companies}}
which outputs
<LI> Company Name </LI>
Above this I have a text box, and would like to filter the list of companies by what I type in the textbox - I'd prefer to have a "containing" filter as opposed to "starting with" filter, but i'll take either one - is there an established way of doing this in Meteor? If not, is there a plugin that someone wrote that does this?
Also, whatever answer you give, please consider the fact that I've been using Meteor for, oh, 5 days now, and i'm still learning it, so, a Newbie style answer would be great.
Thanks for Reading!
edit
This is the updated answer I came up with - combining David's answer with my previous companies helper:
Template.companyList.helpers({
companies: function () {
var query = Session.get('query');
selector = {owner: Meteor.userId()};
options = {sort: {a: 1}, companyName:1, createdAt:1};
if (query && query.length) {
var re = new RegExp(query, 'i');
selector.companyName = re;
}
return Companies.find(selector, options);
}
});
Here is the outline for a simple search-as-you-type interface:
Template.myTemplate.helpers({
companies: function() {
// build a regular expression based on the current search
var search = Session.get('search');
var re = new RegExp(search, 'i');
selector = {owner: Meteor.userId()};
// add a search filter only if we are searching
if (search && search.length)
selector.name = re;
options = {sort: {createdAt: -1}};
return Companies.find(selector, options);
}
});
Template.myTemplate.events({
'keyup #search': function() {
// save the current search query in a session variable as the user types
return Session.set('search', $('#search').val());
}
});
This assumes:
You are trying to search Companies by name.
You have an input with an id of search.
Please modify as needed for your use case. Let me know if you have any questions.
hope my first question here is not a stupid one.
Lets say we want to build a chat application with meteor, with logedin and anonymous users. The chat should be filled like that:
var post = {
userId: user._id, // is empty if anonymous user
submitted: new Date().getTime(),
text: chat_message
});
var postId = Posts.insert(post);
The publication could looks like this to make sure that the userId is not transfered
Meteor.publish('getTheChat', function() {
return Post.find({}, {fields: {userId: false});
});
But is there a way to add a field in the returned collection dynamically?
The userId should not be published but a status like "Your_Post","another_logedin_user" or "an_anonymous_user". By having that, I could include some css, so the chat looks a little bit more like WhatsApp or iMessage.
The logic inside the publish method could be something like
if (userId == this.userId) {
status = "Your_Post";
} else if (userId != null) {
status = "another_logedin_user";
} else {
status = "an_anonymous_user";
}
You see, the publication should include different values when called from different users. Is there a way in Meteor.publish?
Thanks for any insight or suggestions
Thank you both for your ideas! But as I had to find out (just for my inward peace) how it is possible inside the publish method server sided, I came, with the help of David's link, to this solution -maybe it will help someone later:
Meteor.publish('getTheChat', function(postId) {
var currentUserId = this.userId;
var ownerUserId = Posts.findOne({'_id':postId}).userId;
var findOptions = {}; // in my final coding these differ for 'chat room owners' and 'normal users'
var transform = function(post) {
if (currentUserId && post.userId == currentUserId) {
post.userId = "posted by you";
} else if (post.userId == null) {
post.userId = "anonym posted";
} else if (post.userId == ownerUserId) {
post.userId = "posted by owner";
} else {
post.userID = "posted by another loged in";
return post;
};
var self = this;
var handle = Posts.find(findOptions).observe({
added: function (document) {
self.added('posts', document._id, transform(document));
},
changed: function (newDocument, oldDocument) {
self.changed('posts', document._id, transform(newDocument));
},
removed: function (oldDocument) {
self.removed('posts', oldDocument._id);
}
});
self.ready();
self.onStop(function(){
handle.stop();
});
By having this I am finally able to overwrite values dynamically.
It looks like you need to add a transform on your Posts collection. You can do this in your publish function (as seen here), but server-side transforms are computationally inefficient and tricky to write. Though they are necessary in cases where only the server could perform the action - e.g. signed URLs. In your case, I'd recommend a standard collection transform which is a filter applied after the documents are fetched.
Unfortunately, this kind of transform would require the userId on the client. I've never seen a case where simply publishing a id could cause a security issue. If you believe this is the case with your app, I'm very interested to know why. If you can overcome this restriction, keep reading...
You can read about transforms in the documentation on collections, and you can see an example on evented mind. Personally I like to use the collection-helpers package for this.
If you try collection-helpers, your transform could look like:
Posts.helpers({
status: function() {
if (this.userId === Meteor.userId()) {
return 'Your_Post';
} else if (this.userId != null) {
return 'another_logedin_user';
} else {
return 'an_anonymous_user';
}
}
});
And then you could use it in your template like:
{{#each posts}}
<p>{{text}} - <span class='status'>{{status}}</span></p>
{{/each}}
Of course, you can also use template helpers to achieve the same result but transforms are more easily reusable across your application.
Sadly, this has been a huge issue for me too, and I am sorry to say, it is not technically possible to just add a field on the publisher's query and use it conveniently in your view. BUT, I have a solution that may work for you. It will also give you an idea of how complex it can become as soon as you want to keep some reactive data private in Meteor.
Server side:
First, create two different publishers: one for the current user's posts, one for all the others:
Meteor.publish('getTheOthersChat', function() {
return Post.find({$ne:{userId: this.userId}}, {fields: {userId: false});
});
Meteor.publish('getTheOwnChat', function() {
return Post.find({userId: this.userId});
});
Client/router side:
Then, subscribe to both of these: what this will do is include the post's userId only when it is the own user's id. If not, it'll be undefined.
Then, we still need to identify the case "anonymously posted" vs "posted by user". For this, you can add another field during the post creation, for example is_anonymous, which you then set to true or false depending on the case if the user is logged in or not. The check would then be:
if (userId) {
status = "Your_Post";
} else if (is_anonymous === false) {
status = "another_logedin_user";
} else {
status = "an_anonymous_user";
}
This solution should work. I know, it is sad to have to come to this kind of means. It makes Meteor look clunky and impractical for tasks that should be dead easy. Such a shame for such a cool framework!
I have client side only (local) Meteor collection defined like that (coffeescript):
Products = new Meteor.Collection null
However when I try to find() providing sorting parameters Meteor tells me that sorting of local collections is not supported. This is understandable.
I would like to know what is the easiest/simplest way to get sorted results. Essentially I always use all the data in the Collection, so keeping it in sorted state would solve the problem.
It works for me, are you using the latest version of Meteor? Running this code works on the Meteor Docs site:
var foos = new Meteor.Collection( null );
for ( var i = 0; i < 100; i++ ) {
foos.insert({ num: i });
}
foos.findOne( {} ).num; // => 0
foos.findOne( {}, { sort: [[ "num", "desc" ]] } ).num; // => 99