I'm not sure why the removal doesn't work using the latter method. (foundList is not null)
Latter method:
List.findOne({name: listType}, function(err, foundList){
if (err){
console.log(err);
} else {
foundList.updateOne({}, { $pull: { item: { _id: itemID } } });
console.log('deletion success');
res.redirect("/" + listType);
}
});
}
Schema:
const itemSchema = {text: String}
const listSchema = {
name: String,
item: [itemSchema]
}
Below line is wrong and wont work. This is because foundList contains result of the query findOne.
foundList.updateOne({}, { $pull: { item: { _id: itemID } } });
After you call List.findOne({name: listType}, function(err, foundList), foundList contains result of the query, and you cannot call any query/mongoose-api on that. You need to call mongoose APIs like updateOne on the model object, only then you will get the result.
What you can do is you can modify that document and then save it. You can do that like this:
List.findOne({name: listType}, function(err, foundList){
if (err){
console.log(err);
} else {
let index = foundList.findIndex((list: any) => list.item._id == itemID );
if (index !== -1) {
foundList.splice(index, 1);
}
foundList.save().then(()=>{
console.log('deletion success');
res.redirect("/" + listType);
})
}
})
Or you can do all that in one query. Try this:
List.findOneAndUpdate({name: listType}, {
$pull: {
item: { _id: itemID }
}, {new:true})
.then((response) => {
console.log('deletion success');
res.redirect("/" + listType);
})
.catch((err) => res.json(err));
NOTE: Also make sure itemID is of type ObjectId and not string. You can typecast string to ObjectId as shown here.
Related
I'm trying to update an item in a mongoDB, but I can't get it to work properly. I've googled the question and I can't seem to find what I'm doing wrong. I don't get any errors in the console, it actually says the update was successful. So far I've been able to create and find items in the DB just fine..Here's my code if anyone can help me spot the problem I'd really appreciate it!
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/fruits", { useNewUrlParser: true, useUnifiedTopology: true });
const fruitSchema = new mongoose.Schema({
name: String,
rating: Number
});
const Fruit = mongoose.model("Fruit", fruitSchema);
// CREATE
// Fruit.create({
// name: "Grape",
// rating: "7"
// }, (err, fruit) => {
// if (err) {
// console.log(err);
// } else {
// console.log("SAVED FRUIT!");
// console.log(fruit);
// }
// });
// READ
// Fruit.findById({ _id: "5f85e2e36ef7e00c97ac484f" }, (err, fruit) => {
// if (err) {
// console.log(err);
// } else {
// console.log("FOUND FRUIT!");
// console.log(fruit);
// }
// });
// UPDATE
Fruit.findByIdAndUpdate({ _id: "5f85e2e36ef7e00c97ac484f" }, { $set: { color: "Green" } }, (err, fruit) => {
if (err) {
console.log(err);
} else {
console.log("UPDATED FRUIT!");
console.log(fruit);
}
});
Here's what the DB looks like,
{
"_id" : ObjectId("5f85e2e36ef7e00c97ac484f"),
"name" : "Kiwi",
"rating" : 6,
"__v" : 0
}
{
"_id" : ObjectId("5f85e3003dbb9d0c9bcca90d"),
"name" : "Grape",
"rating" : 7,
"__v" : 0
}
Define color in mongoose schema
const fruitSchema = new mongoose.Schema({
name: String,
rating: Number,
color: String // add this one.
});
Also while updating, no need to use $set, just pass the object.
Fruit.findByIdAndUpdate({ _id: "5f85e2e36ef7e00c97ac484f" }, { color: "Green" }, (err, fruit) => {
if (err) {
console.log(err);
} else {
console.log("UPDATED FRUIT!");
console.log(fruit);
}
});
Hy I'm using the Apollo Client with React. I query the posts with many different variables. So I have one post in different "caches". Now I want to delete a post. So I need to delete this specific post from all "caches".
const client = new ApolloClient({
link: errorLink.concat(authLink.concat(httpLink)),
cache: new InMemoryCache()
});
Postquery:
export const POSTS = gql`
query posts(
$after: String
$orderBy: PostOrderByInput
$tags: JSONObject
$search: String
$orderByTime: Int
) {
posts(
after: $after
orderBy: $orderBy
tags: $tags
search: $search
orderByTime: $orderByTime
) {
id
title
...
}
}
`;
I tried it with the cache.modify(), which is undefined in my mutation([https://www.apollographql.com/docs/react/caching/cache-interaction/#cachemodify][1])
const [deletePost] = useMutation(DELETE_POST, {
onError: (er) => {
console.log(er);
},
update(cache, data) {
console.log(cache.modify())//UNDEFINED!!!
cache.modify({
id: cache.identify(thread), //identify is UNDEFINED + what is thread
fields: {
posts(existingPosts = []) {
return existingPosts.filter(
postRef => idToRemove !== readField('id', postRef)
);
}
}
})
}
});
I also used the useApolloClient() with the same result.
THX for any help.
Instead of using cache.modify you can use cache.evict, which makes the code much shorter:
deletePost({
variables: { id },
update(cache) {
const normalizedId = cache.identify({ id, __typename: 'Post' });
cache.evict({ id: normalizedId });
cache.gc();
}
});
this option worked for me
const GET_TASKS = gql`
query tasks($listID: String!) {
tasks(listID: $listID) {
_id
title
sort
}
}
`;
const REMOVE_TASK = gql`
mutation removeTask($_id: String) {
removeTask(_id: $_id) {
_id
}
}
`;
const Tasks = () => {
const { loading, error, data } = useQuery(GET_TASKS, {
variables: { listID: '1' },
});
сonst [removeTask] = useMutation(REMOVE_TASK);
const handleRemoveItem = _id => {
removeTask({
variables: { _id },
update(cache) {
cache.modify({
fields: {
tasks(existingTaskRefs, { readField }) {
return existingTaskRefs.filter(
taskRef => _id !== readField('_id', taskRef),
);
},
},
});
},
});
};
return (...);
};
You can pass your updater to the useMutation or to the deletePost. It should be easier with deletePost since it probably knows what it tries to delete:
deletePost({
variables: { idToRemove },
update(cache) {
cache.modify({
fields: {
posts(existingPosts = []) {
return existingPosts.filter(
postRef => idToRemove !== readField('id', postRef)
);
},
},
});
},
});
You should change variables to match your mutation. This should work since posts is at top level of your query. With deeper fields you'll need a way to get the id of the parent object. readQuery or a chain of readField from the top might help you with that.
Checking the router on the server side it console logs the right values, only the follow error is popping up in here. Trying to build a counter that should update the value on the backend. But the problem I have is that value will not be stored in there. When using Postman the value will be stored successfully. What is the solution that can fix this issue.
export const incrementProduct = (index, updateAmount, id) => {
return dispatch => {
dispatch(increment(index));
try {
axios.patch(`${API_URL}/:${id}`, {
amount: updateAmount
}).then(res => {
console.log(res.config);
})
} catch(err) {
console.log(err)
}
}
}
const PostSchema = mongoose.Schema({
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
amount: {
type: Number,
required: true
},
editable: {
type: Boolean,
required: true
},
data: {
type: Date,
default: Date.now
}
});
// update
router.patch('/:postId', async(req, res) => {
console.log('update', req.params.postId + 'amount ' + req.body.amount)
try {
const updatedPost = await Post.findByIdAndUpdate(
{_id: req.params.postId}, <--- this cause the console error...
{$set:
{
amount: req.body.amount
},
})
console.log('try')
res.json(updatedPost)
} catch(err) {
console.log(err + 'test ')
res.json({ message: err })
}
})
You need to remove : in the patch url like this:
axios.patch(`${API_URL}/${id}`
Also findByIdAndUpdate requires only the value of _id, so you can only pass the value like this:
await Post.findByIdAndUpdate(req.params.postId, ...
findByIdAndUpdate(id, ...) is equivalent to findOneAndUpdate({ _id: id }, ...).
I am trying to update multiple docs in mongo.
I have an array, and I want to update multiple mongo docs with a specific object from that array.
let items = [{ order: 0 }, { order: 1 }, { order: 2 }]
I have tried this for updating mongo:
items.map((item) => {
db.items.findOneAndUpdate(
{ _id: item._id },
{ $set: { order: item.order } }
)
})
If I check items, it has actually updated the array:
console.log(items)
But when I look in my database, MongoDB has not updated.
Any suggestions what I'm doing wrong?
Thanks!
map is a synchronous function and you are using it to for an asynchronous update with findOneAndUpdate, akin to mixing water and oil.
You either need to use async/await or Promise.all with the map function. For example, with the above, you can create an array of promises with the map function and resolve with Promise.all
const updatePromises = items.map(({ _id, order }) => (
Item.findOneAndUpdate({ _id }, {'$set': { order } })
))
Promise.all(updatePromises).then(console.log).catch(console.error)
Using async/await
(async () => {
try {
for(let i=0; i<items.length; i++) {
await Item.findOneAndUpdate(
{ _id: item._id },
{ $set: { order: item.order } }
)
}
} catch (err) {
console.error(err)
}
})()
With Meteor (1.4.2.3) and React, I have the collection Objects which has an itemId which refers to the collection Items.
Currently I subscribe to the collection on the client side with:
export default createContainer(() => {
let objectsSub = Meteor.subscribe('allObjects');
var objects = Objects.find({}, {
transform: function (doc) {
doc.item = Items.findOne({
_id: doc.itemId
});
return doc;
}
}).fetch();
return {
objects: objects,
}
}, App);
This works perfect, but I think it is more elegant to merge the collections on the server side. However, none of the solutions I found seem to work
Transform at collection definition
const Objects = new Mongo.Collection('objects',
{
transform: function (doc) {
doc.item = Items.findOne({
_id: doc.itemId
})
}
});
The console gives:
Error: transform must return object
Transform at publish
if (Meteor.isServer) {
Meteor.publish('allObjects', function () {
return Objects.find({}, {
sort: { startedAt: -1 },
transform: function (doc) {
doc.item = Items.findOne({
_id: doc.itemId
});
return doc;
}
});
});
};
TypeError: Cannot read property 'name' of undefined
Where name is a property of Items
i usually do it in the publish like this:
Meteor.publish('allObjects', function () {
let cursor = Objects.find({}, {
sort: { startedAt: -1 });
});
let transformData = (fields) => {
fields.item = Items.findOne({
_id: fields.itemId
});
return fields;
};
let handle = cursor.observeChanges({
added: (id, fields) => {
fields = transformData(fields);
this.added('objects', id, fields);
},
changed: (id, fields) => {
fields = transformData(fields);
this.changed('objects', id, fields);
},
removed: (id) => {
this.removed('objects', id);
}
});
this.ready();
this.onStop(() => {
handle.stop();
});
}