realm@10.5.0 版本中的新增功能。
Realm集是一种特殊对象,允许您存储唯一值的集合。 Realm集基于JavaScript 集 ,但只能包含单一类型的值,并且只能在写事务(write transaction)中修改。 Set 允许您执行数学运算,例如查找两个 Set 之间的并集、交集或差值。要学习;了解有关执行这些操作的更多信息,请参阅 MDN 文档中的“实施基本设立操作”。
Realm 对象模型
您可以通过两种方式将 Realm 对象模型属性类型定义为 Realm 集:
指定 Set 将包含的数据类型,紧接着是
<>。对于更复杂的属性,请使用对象符号和
type字段。
1 class Character extends Realm.Object { 2 static schema = { 3 name: 'Character', 4 primaryKey: '_id', 5 properties: { 6 _id: 'objectId', 7 name: 'string', 8 levelsCompleted: 'int<>', 9 inventory: { 10 type: 'set', 11 objectType: 'string', 12 }, 13 }, 14 }; 15 }
1 class Character extends Realm.Object<Character> { 2 _id!: Realm.BSON.ObjectId; 3 name!: string; 4 levelsCompleted!: Realm.Set<number>; 5 inventory!: Realm.Set<string>; 6 7 static schema: ObjectSchema = { 8 name: 'Character', 9 primaryKey: '_id', 10 properties: { 11 _id: 'objectId', 12 name: 'string', 13 levelsCompleted: 'int<>', 14 inventory: { 15 type: 'set', 16 objectType: 'string', 17 }, 18 }, 19 }; 20 }
使用集合创建对象
要创建具有 Realm 集属性的对象,您必须在写事务中创建该对象。定义 Realm 对象时,通过传递空数组或具有初始值的数组来初始化 Realm 集。
例子
在以下CreateInitialCharacters组件示例中,我们创建具有 Set 属性的Character对象。
CreateInitialCharacters 组件将执行以下操作:
通过调用该组件中的
useRealm()钩子来访问打开的 Realm 实例。使用 React 的 useEffect 钩子通过
useEffect和空依赖大量仅调用匿名函数一次。在匿名函数中,我们在写事务(write transaction)中创建了两个不同的Character对象。我们设立inventory和levelsCompleted为具有初始值的大量。通过将
Character类传递给useQuery()钩子,检索 Realm 实例中的所有字符。在用户界面中将每个字符的名字显示为
Text元素。
1 const CreateInitialCharacters = () => { 2 const realm = useRealm(); 3 useEffect(() => { 4 realm.write(() => { 5 realm.create('Character', { 6 _id: new Realm.BSON.ObjectId(), 7 name: 'AdventurousPlayer', 8 inventory: ['elixir', 'compass', 'glowing shield'], 9 levelsCompleted: [4, 9], 10 }); 11 }); 12 realm.write(() => { 13 realm.create('Character', { 14 _id: new Realm.BSON.ObjectId(), 15 name: 'HealerPlayer', 16 inventory: ['estus flask', 'gloves', 'rune'], 17 levelsCompleted: [1, 2, 5, 24], 18 }); 19 }); 20 }, []); 21 const characters = useQuery(Character); 22 23 return ( 24 <View> 25 {characters.map(character => ( 26 <View key={character._id}> 27 <Text>{character.name}</Text> 28 </View> 29 ))} 30 </View> 31 ); 32 };
1 const CreateInitialCharacters = () => { 2 const realm = useRealm(); 3 useEffect(() => { 4 realm.write(() => { 5 realm.create('Character', { 6 _id: new Realm.BSON.ObjectId(), 7 name: 'AdventurousPlayer', 8 inventory: ['elixir', 'compass', 'glowing shield'], 9 levelsCompleted: [4, 9], 10 }); 11 }); 12 13 realm.write(() => { 14 realm.create('Character', { 15 _id: new Realm.BSON.ObjectId(), 16 name: 'HealerPlayer', 17 inventory: ['estus flask', 'gloves', 'rune'], 18 levelsCompleted: [1, 2, 5, 24], 19 }); 20 }); 21 }, []); 22 const characters = useQuery(Character); 23 24 return ( 25 <View> 26 {characters.map(character => ( 27 <View key={character._id}> 28 <Text>{character.name}</Text> 29 </View> 30 ))} 31 </View> 32 ); 33 };
将项目添加到 Set 中
要将列项添加到集中,请将新值传递给写事务中的 Realm.Set.add() 方法。
例子
在以下 AddInventoryToCharacter 组件示例中,我们将新的集元素添加到字符库存。
AddInventoryToCharacter 组件将执行以下操作:
通过调用该组件中的
useRealm()钩子来访问打开的 Realm 实例。创建称为“inventoryItem”的状态变量,表示要向库存集添加的新库存项目。
通过将
Character类传递给useQuery()钩子并运行Collection.filtered() 来检索字符方法,用于过滤名称与characterName属性 匹配的字符。然后,我们将变量character设立为第一个匹配结果。创建用于执行写事务的组件方法
addInventoryItem(),写事务通过将inventoryItem状态变量传递到Realm.Set.add()来将库存项目添加至字符库存中。呈现更改
inventoryItem状态变量的TextInput和调用addInventoryItem()方法的Button。
1 const AddInventoryToCharacter = ({characterName}) => { 2 const realm = useRealm(); 3 const [inventoryItem, setInventoryItem] = useState(''); 4 const character = useQuery( 5 Character, 6 characters => { 7 return characters.filtered(`name = '${characterName}'`); 8 }, 9 [characterName], 10 )[0]; 11 12 const addInventoryItem = () => { 13 realm.write(() => { 14 character?.inventory.add(inventoryItem); 15 }); 16 }; 17 18 return ( 19 <View> 20 <TextInput 21 onChangeText={text => setInventoryItem(text)} 22 value={inventoryItem} 23 /> 24 <Button 25 title='Add Inventory Item' 26 onPress={addInventoryItem} 27 /> 28 </View> 29 ); 30 };
1 const AddInventoryToCharacter = ({ 2 characterName, 3 }: { 4 characterName: string; 5 }) => { 6 const realm = useRealm(); 7 const [inventoryItem, setInventoryItem] = useState(''); 8 const character = useQuery( 9 Character, 10 characters => { 11 return characters.filtered(`name = '${characterName}'`); 12 }, 13 [characterName], 14 )[0]; 15 16 const addInventoryItem = () => { 17 realm.write(() => { 18 character?.inventory.add(inventoryItem); 19 }); 20 }; 21 22 return ( 23 <View> 24 <TextInput 25 onChangeText={text => setInventoryItem(text)} 26 value={inventoryItem} 27 /> 28 <Button 29 title='Add Inventory Item' 30 onPress={addInventoryItem} 31 /> 32 </View> 33 ); 34 };
检查集是否有特定项并检查集的大小
您可能需要检查有关您的 Set 的信息,例如其大小或是否包含特定项目。
要确定 Set 是否包含特定值,请将该值传递给Realm.Set.has() 方法。 如果集包含指定的值,则此方法将返回true 。
要了解集有多少列项,您可以检查其 size 属性。
例子
在以下QueryCharacterInventory组件的示例中,我们检查字符的库存大小以及它是否具有特定项目。
QueryCharacterInventory 组件将执行以下操作:
创建称为“inventoryItem”的状态变量,表示您要在字符库存中搜索的库存项目。
使用
useQuery钩子对所有字符执行查询,并筛选结果以仅包括名称与作为 prop 传递给组件的characterName相匹配的字符。然后,我们得到第一个匹配结果。通过将
Character类传递给useQuery()钩子并运行Collection.filtered()来检索字符 方法,用于筛选名称与characterName属性匹配的字符。 然后,我们将变量character设置为第一个匹配结果。创建一个组件方法
queryCharacterInventory,将inventoryItem状态变量传递给Realm.Set.has(),以检查字符库存中是否包含该项目。 如果字符库存中包含该项目,则该方法会提醒该字符拥有该项目。如果字符库存中不包含该项目,则该方法会提醒该字符没有该项目。呈现字符名称,并使用字符库存的
size属性呈现库存大小。 它还呈现一个用于更改inventoryItem状态变量的TextInput,以及一个调用queryCharacterInventory方法的Button。
1 const QueryCharacterInventory = ({characterName}) => { 2 const [inventoryItem, setInventoryItem] = useState(''); 3 const character = useQuery( 4 Character, 5 characters => { 6 return characters.filtered(`name = '${characterName}'`); 7 }, 8 [characterName], 9 )[0]; 10 11 const queryCharacterInventory = () => { 12 const characterDoesHaveItem = character.inventory.has(inventoryItem); 13 if (characterDoesHaveItem) { 14 Alert.alert(`Character has item: ${inventoryItem}`); 15 } else { 16 Alert.alert(`Item not found in character's inventory`); 17 } 18 }; 19 return ( 20 <View> 21 <Text>{character.name}</Text> 22 <Text> 23 Total number of inventory items: {character.inventory.size} 24 </Text> 25 <TextInput 26 onChangeText={text => setInventoryItem(text)} 27 value={inventoryItem} 28 /> 29 <Button 30 title='Query for Inventory' 31 onPress={queryCharacterInventory} 32 /> 33 </View> 34 ); 35 };
1 const QueryCharacterInventory = ({ 2 characterName, 3 }: { 4 characterName: string; 5 }) => { 6 const [inventoryItem, setInventoryItem] = useState(''); 7 const character = useQuery( 8 Character, 9 characters => { 10 return characters.filtered(`name = '${characterName}'`); 11 }, 12 [characterName], 13 )[0]; 14 15 const queryCharacterInventory = () => { 16 const characterDoesHaveItem: Boolean = 17 character.inventory.has(inventoryItem); 18 if (characterDoesHaveItem) { 19 Alert.alert(`Character has item: ${inventoryItem}`); 20 } else { 21 Alert.alert(`Item not found in character's inventory`); 22 } 23 }; 24 return ( 25 <View> 26 <Text>{character.name}</Text> 27 <Text> 28 Total number of inventory items: {character.inventory.size} 29 </Text> 30 <TextInput 31 onChangeText={text => setInventoryItem(text)} 32 value={inventoryItem} 33 /> 34 <Button 35 title='Query for Inventory' 36 onPress={queryCharacterInventory} 37 /> 38 </View> 39 ); 40 };
删除 Set 信息
您可能想要从 Set 中删除特定项目或所有项目。
要从集中删除特定值,请将该值传递给写事务中的 Realm.Set.delete() 方法。
要清除集,请运行写事务中的 Realm.Set.clear() 方法。
例子
在以下 RemoveInventoryFromCharacter 组件示例中,我们从集中删除了特定项目并清除了集中的所有项目。
RemoveInventoryFromCharacter 组件将执行以下操作:
通过调用该组件中的
useRealm()钩子来访问打开的 Realm 实例。创建称为“inventoryItem”的状态变量,表示要从库存 Set 中删除的库存项目。
创建一个组件方法
removeInventoryItem,将inventoryItem状态变量传递给Realm.Set.delete(),以从字符库存中删除该项目。创建组件方法
removeAllInventory,该方法调用Realm.Set.clear(),从字符库存删除所有列项。呈现一个用于更改
inventoryItem状态变量的TextInput,以及两个分别调用removeInventoryItem和removeAllInventory方法的Button组件。
1 const RemoveInventoryFromCharacter = ({characterName}) => { 2 const realm = useRealm(); 3 const [inventoryItem, setInventoryItem] = useState(''); 4 const character = useQuery( 5 Character, 6 characters => { 7 return characters.filtered(`name = '${characterName}'`); 8 }, 9 [characterName], 10 )[0]; 11 12 const removeInventoryItem = () => { 13 realm.write(() => { 14 character?.inventory.delete(inventoryItem); 15 }); 16 }; 17 const removeAllInventory = () => { 18 realm.write(() => { 19 character?.inventory.clear(); 20 }); 21 }; 22 return ( 23 <View> 24 <Text>{character.name}</Text> 25 <TextInput 26 onChangeText={text => setInventoryItem(text)} 27 value={inventoryItem} 28 /> 29 <Button 30 title='Remove Inventory Item' 31 onPress={removeInventoryItem} 32 /> 33 <Button 34 title='Remove All Inventory' 35 onPress={removeAllInventory} 36 /> 37 </View> 38 ); 39 };
1 const RemoveInventoryFromCharacter = ({ 2 characterName, 3 }: { 4 characterName: string; 5 }) => { 6 const realm = useRealm(); 7 const [inventoryItem, setInventoryItem] = useState(''); 8 const character = useQuery( 9 Character, 10 characters => { 11 return characters.filtered(`name = '${characterName}'`); 12 }, 13 [characterName], 14 )[0]; 15 16 const removeInventoryItem = () => { 17 realm.write(() => { 18 character?.inventory.delete(inventoryItem); 19 }); 20 }; 21 const removeAllInventory = () => { 22 realm.write(() => { 23 character?.inventory.clear(); 24 }); 25 }; 26 return ( 27 <View> 28 <Text>{character.name}</Text> 29 <TextInput 30 onChangeText={text => setInventoryItem(text)} 31 value={inventoryItem} 32 /> 33 <Button 34 title='Remove Inventory Item' 35 onPress={removeInventoryItem} 36 /> 37 <Button 38 title='Remove All Inventory' 39 onPress={removeAllInventory} 40 /> 41 </View> 42 ); 43 };
遍历集
您可以遍历集合以访问权限集合中的每个项目。要遍历集,请使用 Set.map() 方法或替代迭代方法。
但是,默认下,不保证集中项目的顺序。要按顺序遍历集合,可以将集合的项目存储在状态变量中,并在向集合添加新项目时更新该状态变量。
例子
在以下 TraverseCharacterInventory 组件示例中,字符开始时没有库存列项。当用户将列项添加到库存集中时,该组件将以有序和无序列表的形式显示集中的每个列项。
TraverseCharacterInventory 组件将执行以下操作:
通过调用该组件中的
useRealm()钩子来访问打开的 Realm 实例。创建一个名为“inventoryItem”的状态变量,表示要添加到库存集中的新库存项目。
创建一个名为"inventory"的状态变量,将按插入顺序保存字符的库存项目。
通过将
Character类传递给useQuery()钩子并运行Collection.filtered() 来检索字符方法,用于过滤名称与characterName属性 匹配的字符。然后,我们将变量character设立为第一个匹配结果。创建用于执行写事务的组件方法
addInventoryItem(),该写事务通过将inventoryItem状态变量传递给Realm.Set.add()来将库存项目添加到字符的库存中。 方法。 写事务完成后,该方法将inventoryItem添加到inventory数组状态变量。呈现更改
inventoryItem状态变量的TextInput和调用addInventoryItem()方法的Button。通过遍历
inventory数组状态变量,按照添加到集中的顺序呈现字符的库存列项的列表。通过遍历
character.inventory呈现字符库存的无序列表。
1 const TraverseCharacterInventory = ({characterName}) => { 2 const realm = useRealm(); 3 const [inventoryItem, setInventoryItem] = useState(''); 4 const [inventory, setInventory] = useState([]); 5 6 const character = useQuery( 7 Character, 8 characters => { 9 return characters.filtered(`name = '${characterName}'`); 10 }, 11 [characterName], 12 )[0]; 13 14 const addInventoryItem = () => { 15 realm.write(() => { 16 character?.inventory.add(inventoryItem); 17 }); 18 setInventory([...inventory, inventoryItem]); 19 }; 20 21 return ( 22 <View> 23 <Text>{character.name}</Text> 24 <Text>Add an item to the inventory:</Text> 25 <TextInput 26 onChangeText={text => setInventoryItem(text)} 27 value={inventoryItem} 28 /> 29 <Button 30 title='Add Inventory Item' 31 onPress={addInventoryItem} 32 /> 33 34 <Text>Ordered Inventory:</Text> 35 {inventory.map(item => ( 36 <Text>{item}</Text> 37 ))} 38 39 <Text>Unordered Inventory:</Text> 40 {character.inventory.map(item => ( 41 <Text>{item}</Text> 42 ))} 43 </View> 44 ); 45 };
1 const TraverseCharacterInventory = ({ 2 characterName, 3 }: { 4 characterName: string; 5 }) => { 6 const realm = useRealm(); 7 const [inventoryItem, setInventoryItem] = useState<string>(''); 8 const [inventory, setInventory] = useState<string[]>([]); 9 10 const character = useQuery( 11 Character, 12 characters => { 13 return characters.filtered(`name = '${characterName}'`); 14 }, 15 [characterName], 16 )[0]; 17 18 const addInventoryItem = () => { 19 realm.write(() => { 20 character?.inventory.add(inventoryItem); 21 }); 22 setInventory([...inventory, inventoryItem]); 23 }; 24 25 return ( 26 <View> 27 <Text>{character.name}</Text> 28 <Text>Add an item to the inventory:</Text> 29 <TextInput 30 onChangeText={text => setInventoryItem(text)} 31 value={inventoryItem} 32 /> 33 <Button 34 title='Add Inventory Item' 35 onPress={addInventoryItem} 36 /> 37 38 <Text>Ordered Inventory:</Text> 39 {inventory.map(item => ( 40 <Text>{item}</Text> 41 ))} 42 43 <Text>Unordered Inventory:</Text> 44 {character.inventory.map(item => ( 45 <Text>{item}</Text> 46 ))} 47 </View> 48 ); 49 };