i have a post collection that contains an embedded array of comments.
in each post view page, i need to publish 2 cursors: one witch contains all posts without their comments field (performance) to show in some widget, and another witch contains the selected post with it's comments. server side code looks like:
Meteor.publish('allPosts', function() {
return Posts.find({}, {fields: {'comments':0}})
})
Meteor.publish('singlePost', function(slug) {
return Posts.find({slug: slug})
})
in post view template, i subscribe for both of these, but when i use
Posts.findOne({slug: slug})
how can i know witch publication cursor is used? how can i choose one?
When you query Posts on the client, you are querying the union of all active subscriptions on that collection. In this case, if you have subscribed to singlePost with that particular slug, you will get the full document. If you have not, you will not get the comments.
Another example:
Meteor.publish("allSummaries", function () {
return Posts.find({}, {fields: {title: 1, date: 1}});
});
Meteor.publish("myPosts", function () {
return Posts.find({creator: this.userId}, {fields: {title: 1, rating: 1}});
});
Meteor.publish("singlePost", function (_id) {
return Posts.find({_id: _id}, {fields: {title: 1, body: 1});
});
Suppose a client with userId "me" is subscribed to allSummaries, myPosts and singlePost (with _id of "3"). The collection contains these documents:
{_id: "1", title: "Post 1", date: "yesterday", creator: "someone else", rating: 3}
{_id: "2", title: "Post 2", date: "today", creator: "me", rating: 4}
{_id: "3", title: "Post 3", date: "5 days ago", creator: "someone else", rating: 2}
For Post 1, the client will only see title and date (and _id) - published from allSummaries - but nothing else. For post 2, they will see title, date, and rating - the date comes from allSummaries, the title from both allSummaries and myPosts, and rating from myPosts. For post 3, they will see title, date and body, but not rating.
Related
I am trying to access document _id in the client
Here is how I am publishing it:
Meteor.publish('events', function () {
return Requests.find({}, {fields: {"_id": 1, 'start': 1, 'title': 1, 'reasons': 1}});
});
and in the client when I try to console.log() the id, I get "_fc4" printed to the console
Here is my code (in the client):
eventClick: function(event, jsEvent, view) {
console.log(event._id);
}
event is the documents returned. I get the correct value when printing event.title, event.start, or event.reasons to the console. But I get _fc4 when trying event._id.
My question now is, how to publish the _id correctly?
NOTE: Tried to change "_id" with _id and received the same results in the console
I believe your printing the event id in the calendar, not your document in the database.
make sure you set the event id to your document id before adding it to the calendar
I know the answer to this question might be obvious. But, I still want to have a clear answer.
In Redux, it says: "The state of your whole application is stored in an object tree within a single store".
Let's say we have the following data:
According to the Redux doc, all the data of "todos" should be placed in the store. In the section "Designing state shape", it also says "the minimal representation" of the app.
{
todos: [
{id: 1, description: "Seal the wall"}
{id: 2, description: "Wash the car"}
]
}
If there are only two operations on "todos" like "Add" and "Delete", should the redux store only keep the following data?
{
todos: [1, 2]
}
Operations(Actions) that you perform on your state are completely separate from the state store. The store does not and should not care about what actions are going to happen on it.
So no, the store should not be:
{
todos: [1, 2]
}
and should be:
{
todos: [
{id: 1, description: "Seal the wall"}
{id: 2, description: "Wash the car"}
]
}
I have a meteor publication in which I was trying to use .findOne() to access the fields from the mongodb. But as I cannot return .findOne() from a meteor publish, I am now using just .find(). The problem is that it returns a cursor instead of a document so I am not able to read the values inside that cursor in my publish function.
Below is my mongodb query
var question = Question.find({ "_id": quesId },
{ fields: {"pages": 1, "settings.name": 1, "status": 1 }},
{limit: 1});
And I want to use the value of pages that I get from the above query inside the same publish function
you can set an observer on your cursor and get a hook into the results. i do that frequently to transform the result.
e.g. (i am making the assumption that the publish name is "questions")
let cursor = Question.find({ "_id": quesId }, { "pages": 1, "settings.name": 1, "status": 1 }, {limit: 1});
let handle = cursor.observeChanges({
added: (id, fields) => {
// look at fields
this.added('questions', id, fields);
},
changed: (id, fields) => {
// look at fields
this.changed('questions', id, fields);
},
removed: (id) => {
this.removed('questions', id);
}
});
this.ready();
this.onStop(() => {
handle.stop();
});
this will give you a hook into the records that are added at the initial publish, and changed later. call ready() when your publication is ready to be published (you can see the this.ready() in the sample).
As far as I understand your question, you want to access the single document in the cursor without doing a redundant findOne() in your code. You can transform the result into an array with .fetch() on the cursor, get the first entry with [0] and then directly get the pages attribute.
const question = Question.find(quesId,
{ fields: { "pages": 1, "settings.name": 1, "status": 1 }});
const pages = question.fetch()[0].pages;
Note also that when searching on _id you don't have to specify {_id: quesId} in your filter, you can directly use the value you want to search on as the filter parameter, mongo assumes that you're searching on _id. Furthermore the {limit: 1} is redundant since you're searching on a scalar _id value and so you're guaranteed that the cursor length will be one.
I've been struggling with this for a couple of hours and I can't find a good solution so maybe someone can shed a light on this.
I have a simple schema like this:
var groupschema = new SimpleSchema({
name: {
label: 'Name',
type: String
},
description: {
label: 'Description',
type: String
}
}
And I have another one:
var itemschema = new SimpleSchema({
name: {
label: 'Type:',
type: String
},
details: {
label: 'Details',
type: String
},
group: [groupschema] // <--- this is my main interest
}
If I use the above code sample AutoForm will generate an "inner form" which is quite cool actually for some puporse (e.g. for a contact to have an array of adresses or phone numbers) but for me I would like a drop-down select with the name of the group and when I click on the Insert/Update button (depending on the current form) I would like to add the whole group document to the inserted/updated item document as a subdocument.
Something like this will be inserted to the mongodb:
{
_id: the generated mongoid,
name: "This is a type",
details: "There are some thing to know about this type",
group:{
name: "Cool group",
description: "This is a really cool group"
}
}
The actual documents are far more complicated the above example is just an oversimplified version.
I've stopped writing this question yesterday and tried to do my own version.
My - half baked - solution is:
introducing a new field in the schema named groupselect (type string, autoform type: select)
populate it's contents with a Collection.find().map() lookup
groupselect: {
type: String,
label: 'Group',
optional: true,
blackbox: true,
autoform:{
type: "select",
options : function() {
return Issuegroup.find().map(function (c) {
return {label: c.name , value: c._id};
});
}
}
},
using autoform hooks before insert I assign the subdocument to the real fiel group = Group.find({_id:doc.groupselect}) and I remove the helper field from the doc
using the same technique in the before update hook also for an update form
The problem I seem to be unable to solve in a clean way is to set the default value of the helper field 'groupselect' when the update form displays. I've tried the docToForm hooks but no luck.
Isn't this somehow a very common problem? I imagine there has to be a proper solution for this so I bet that I am missing something very obvious and hopefully someone will point it out for me.
Thanks
Here is a template to demonstrate the issue. The randomArtist is a function that return a document from mongodb. I call the function 3 times, each time I use a different field from that document.
<template name="featuredArtist">
<p>{{randomArtist.artistName}}</p>
<p>{{randomArtist.description}}</p>
<p>{{randomArtist.randId}}</p>
</template>
Here is a template logic.
On the server start up I initialize the collection with some data, so there should be (I think) available for the View part from the beginning.
On the client I get a random document, then store its id (randId) in session to skip lottery during next function call. (PS. It's not the key, but any improvement suggestions are welcome, I'm the beginner in Meteor.)
Artists = new Mongo.Collection("artists");
if (Meteor.isServer) {
Meteor.startup(function () {
Artists.insert({ randId: 0, artistName: "Artis Name 1", image: "url", description: "Description of Artis Name 1"});
Artists.insert({ randId: 1, artistName: "Artis Name 2", image: "url", description: "Description of Artis Name 2" });
Artists.insert({ randId: 2, artistName: "Artis Name 3", image: "url", description: "Description of Artis Name 3" });
Artists.insert({ randId: 3, artistName: "Artis Name 4", image: "url", description: "Description of Artis Name 4" });
Artists.insert({ randId: 4, artistName: "Artis Name 5", image: "url", description: "Description of Artis Name 5" });
});
}
if (Meteor.isClient) {
Meteor.subscribe("artists");
Template.featuredArtist.helpers({
randomArtist: function(){
var randId = Session.get("artistRandId");
if(!randId){
var rand = (Artists.find().count() * Math.random()) | 0;
var artist = Artists.findOne({randId:{$lte:rand}}, {sort: {randId: -1}});
if (!artist) {
artist = Artists.findOne( { randId : { $gte : rand } } );
}
if (!artist) {
console.log('Mongo.Artists is empty');
}
else {
console.log(artist);
Session.set("artistRandId", artist.randId);
return artist;
}
}
else {
console.log('randId='+randId);
return Artists.findOne( { randId: randId } );
}
}
});
}
Working demo is on http://meteorpad.com/pad/MhwXS6MpXQoTYh4Lw/Artists
What I observe in logs is that the 'randomArtist' function is call 7(!) times instead of expected 3 times as it is invoked in the template:
3 times vs expected 0: console.log('Mongo.Artists is empty');
1 time as expected: console.log(artist);
3 times vs expected 2: console.log('randId='+randId);
Can any explain me where are these additional calls come from?
In my real application I can observe more number of calls - probably because I use more complicated templates, does mean that the featureArtist is embedded inside another ones.
It is also unclear how is it possible that in logs I see that the collection is empty as it seems to be populated at start up?
I can't say why your helper is called exactly 7 times, but you can probably get rid of it by using the #with block helper like this:
<template name="featuredArtist">
{{#with randomArtist}}
<p>{{artistName}}</p>
<p>{{description}}</p>
<p>{{randId}}</p>
{{else}}
<p>Got no random artist :(</p>
{{/with}}
</template>
and remove the artistRandId session from your helper. Your helper will probably get called 2 times now, since the template will probably be rendered before the client receives the artist from the artist subscription (the second times occur when the client has received the artists).