I have this code
$scope.users = $meteor.collection( function() {
return AllClients.find({}, {name: 1, _id: 0});
});
I'm expecting to return a value like this
/* 1 */
{
"name" : "Samsung"
}
/* 2 */
{
"name" : "HP"
}
but it still returns a value like this
/* 1 */
{
"_id" : "SqFP23zTXo6MqDLxP",
"code" : "A100",
"name" : "Samsung",
"address" : "Korea"
}
/* 2 */
{
"_id" : "8QtNBoBGrvv5wWpuZ",
"code" : "B100",
"name" : "HP",
"address" : "USA"
}
Is this a bug? Or bad coding...
First off, if you don't want the other bits of information available on the client side, then you need to do the work on the server side. This is handled using publish methods.
Before all, remove autopublish:
> meteor remove autopublish
Then you can create publish method in your server folder:
Meteor.publish('clientNames', function() {
return AllCients.find({}, {fields: {name: 1} });
});
This publish method will find all of the clients and only allow the name field, keep in mind that you may still get the _id field, I believe it's always sent.
Then on your client side you'll need to subscribe to it:
$scope.$meteorSubscribe('clientNames').then(function() {
$scope.users = $scope.$meteorCollection(AllClients, false);
});
With meteor, when you access information form the client side, you only have access to what the server has allowed you to. In this case, you can request AllCients and not have all of the information because the server doesn't allow it.
Related
Making a chatbot that recommends a movie based on genre and other factors. Trying to iterate through an object retrieved from a firebase realtime database in DialogFlow. I'm using forEach but when triggered it displays "Not Available".
Preferably, the function would display a random item from the list but I have not reached that part yet - any advice on this too would be appreciated.
Below is my code.
function displayData(agent) {
return ref.orderByChild("genre1").equalTo("Comedy").on("child_added", function(snapshot) {
let obj = {};
obj = snapshot.val();
obj.forEach(function(childSnapshot) {
var childData = childSnapshot.val();
agent.add(childData.name);
});
});
}
Below is a sample database
{
"movies" : {
"movie1" : {
"genre1" : "Sci-Fi",
"genre2" : "Horror",
"name" : "Alien",
"rating" : 84,
"year" : 1979
},
"movie2" : {
"genre1" : "Comedy",
"genre2" : "Parody",
"name" : "Airplane",
"rating" : 97,
"year" : 1980
},
"movie3" : {
"genre1" : "Comedy",
"genre2" : "Teen",
"name" : "Superbad",
"rating" : 88,
"year" : 2007
}
}
}
The base problem is that the Dialogflow library requires you to return a Promise, however you're using the callback version of the call instead of the Promise version of the call. You need to change this to something more like
function displayData(agent) {
return ref.orderByChild("genre1").equalTo("Comedy").on("child_added")
.then( snapshot => {
// Do something with the snapshot
});
}
(You probably also want to use once("value") instead of on("child_added"), since you don't need updates to be sent in realtime.)
While the forEach() is probably working correctly, there is a minor problem that not all agents will return all the text that has been .add()ed. So you probably only want to call .add() once.
Since you really only want once of these children, picked randomly, you can just treat this as a JavaScript object if you have enough memory. So you could just get the keys with Object.keys(obj), pick one of the keys by random, and then get the full value of the result.
I'm attempting to filter returned data sets with Meteor's find().fetch() to contain just a single object, it doesn't appear very useful if I query for a single subdocument but instead I receive several, some not even containing any of the matched terms.
I have a simple mixed data collection that looks like this:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"name" : "Entertainment",
"items" : [
{
"_id" : ObjectId("57a38b5f2bd9ac8225caff06"),
"slug" : "this-is-a-long-slug",
"title" : "This is a title"
},
{
"_id" : ObjectId("57a38b835ac9e2efc0fa09c6"),
"slug" : "mc",
"title" : "Technology"
}
]
}
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e8"),
"name" : "Sitewide",
"items" : [
{
"_id" : ObjectId("57a38bc75ac9e2efc0fa09c9"),
"slug" : "example",
"name" : "Single Example"
}
]
}
I can easily query for a specific object in the nested items array with the MongoDB shell as this:
db.categories.find( { "items.slug": "mc" }, { "items.$": 1 } );
This returns good data, it contains just the single object I want to work with:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"items" : [
{
"_id" : ObjectId("57a38b985ac9e2efc0fa09c8")
"slug" : "mc",
"name" : "Single Example"
}
]
}
However, if a similar query within Meteor is directly attempted:
/* server/publications.js */
Meteor.publish('categories.all', function () {
return Categories.find({}, { sort: { position: 1 } });
});
/* imports/ui/page.js */
Template.page.onCreated(function () {
this.subscribe('categories.all');
});
Template.page.helpers({
items: function () {
var item = Categories.find(
{ "items.slug": "mc" },
{ "items.$": 1 } )
.fetch();
console.log('item: %o', item);
}
});
The outcome isn't ideal as it returns the entire matched block, as well as every object in the nested items array:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"name" : "Entertainment",
"boards" : [
{
"_id" : ObjectId("57a38b5f2bd9ac8225caff06")
"slug" : "this-is-a-long-slug",
"name" : "This is a title"
},
{
"_id" : ObjectId("57a38b835ac9e2efc0fa09c6")
"slug" : "mc",
"name" : "Technology"
}
]
}
I can then of course filter the returned cursor even further with a for loop to get just the needed object, but this seems unscalable and terribly inefficient while dealing with larger data sets.
I can't grasp why Meteor's find returns a completely different set of data than MongoDB's shell find, the only reasonable explanation is both function signatures are different.
Should I break up my nested collections into smaller collections and take a more relational database approach (i.e. store references to ObjectIDs) and query data from collection-to-collection, or is there a more powerful means available to efficiently filter large data sets into single objects that contain just the matched objects as demonstrated above?
The client side implementation of Mongo used by Meteor is called minimongo. It currently only implements a subset of available Mongo functionality. Minimongo does not currently support $ based projections. From the Field Specifiers section of the Meteor API:
Field operators such as $ and $elemMatch are not available on the client side yet.
This is one of the reasons why you're getting different results between the client and the Mongo shell. The closest you can get with your original query is the result you'll get by changing "items.$" to "items":
Categories.find(
{ "items.slug": "mc" },
{ "items": 1 }
).fetch();
This query still isn't quite right though. Minimongo expects your second find parameter to be one of the allowed option parameters outlined in the docs. To filter fields for example, you have to do something like:
Categories.find(
{ "items.slug": "mc" },
{
fields: {
"items": 1
}
}
).fetch();
On the client side (with Minimongo) you'll then need to filter the result further yourself.
There is another way of doing this though. If you run your Mongo query on the server, you won't be using Minimongo, which means projections are supported. As a quick example, try the following:
/server/main.js
const filteredCategories = Categories.find(
{ "items.slug": "mc" },
{
fields: {
"items.$": 1
}
}
).fetch();
console.log(filteredCategories);
The projection will work, and the logged results will match the results you see when using the Mongo console directly. Instead of running your Categories.find on the client side, you could instead create a Meteor Method that calls your Categories.find on the server, and returns the results back to the client.
I have issue regarding publishing collection.
I have model of each document in collection.
{
"_id" : "8SwmMoMHTREDNDQTN",
"persons" : [
{
"userId" : "29pr753gmyDxQZzo6",
"lastReadTime":""
},
{
"userId" : "gWKbYKiQsFzdCTwkz",
"lastReadTime":""
}
]
}
Now i want to publish document which persons.userId have current user id
Here is my publish code
Meteor.publish("chatRooms", function(){
return userData.find({persons:{$elemMatch:{userId:this.userId}}});
});
But is it is nothing
i had also try below code
Meteor.publish("chatRooms", function(){
return userData.find({"persons.userId":this.userId});
});
But also getting result data 0
How can i publish this way?
I have the following document
{
"_id" : ObjectId("5464e68481f8252e74f6e0ef"),
"message" : "Hello World!",
"timestamp" : ISODate("2014-11-13T17:12:36.547Z"),
"sender" : "D3EkLv8vatX3xfCGE",
"receiver" : [
{
"id" : "YzhZchz4AwCAd3q2R",
"seen" : false
},
{
"id" : "sm2W28EKYmHz29Aoj",
"seen" : false
}
],
"saved" : false
}
That's the basic structure. Now I want to get all the documents that have the current user's ID. The id can be in the sender field or one of the object in the receiver array. This works fine:
db.messages.find({ sender: "D3EkLv8vatX3xfCGE" })
But the following query doesn't work on the Meteor Mongo instance but does so in Mongo 2.6:
db.messages.find({ receiver: {id: "YzhZchz4AwCAd3q2R"} })
Is there any way I can get this to work. Also, the above query works on Minimongo but doesn't work on Meteor's bundled mongo(meteor mongo) which is currently at v2.4.9.
On mongo shell this query seems to work:
db.messages.find({ "receiver.id": "YzhZchz4AwCAd3q2R"} )
You can find all of the documents were a particular user is a receiver using receiver.id in your selector like so:
Messages.find({'receiver.id': 'YzhZchz4AwCAd3q2R'})
If you wanted to find all documents where a particular user was either a receiver or a sender you could do this:
var id = 'YzhZchz4AwCAd3q2R';
Messages.find({$or: [{'receiver.id': id}, {sender: id}]});
all!
I'm new to MongoDB aggregation, after aggregating, I finally get the result:
"result" : [
{
"_id" : "531d84734031c76f06b853f0"
},
{
"_id" : "5316739f4031c76f06b85399"
},
{
"_id" : "53171a7f4031c76f06b853e5"
},
{
"_id" : "531687024031c76f06b853db"
},
{
"_id" : "5321135cf5fcb31a051e911a"
},
{
"_id" : "5315b2564031c76f06b8538f"
}
],
"ok" : 1
The data is just what I'm looking for, but I just want to make it one step further, I hope my data will be displayed like this:
"result" : [
"531d84734031c76f06b853f0",
"5316739f4031c76f06b85399",
"53171a7f4031c76f06b853e5",
"531687024031c76f06b853db",
"5321135cf5fcb31a051e911a",
"5315b2564031c76f06b8538f"
],
"ok" : 1
Yes, I just want to get all the unique id in a plain string array, is there anything I could do? Any help would be appreciated!
All MongoDB queries produce "key/value" pairs in the result document. All MongoDB content is basically a BSON document in this form, which is just "translated" back to native code form by the driver to the language it is implemented in.
So the aggregation framework alone is never going to produce a bare array of just the values as you want. But you can always just transform the array of results, as after all it is only an array
var result = db.collection.aggregate(pipeline);
var response = result.result.map(function(x) { return x._id } );
Also note that the default behavior in the shell and a preferred option is that the aggregation result is actually returned as a cursor from MongoDB 2.6 and onwards. Since this is in list form rather than as a distinct document you would process differently:
var response = db.collection.aggregate(pipeline).map(function(x) {
return x._id;
})